aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Topolnjak <ivantopo@gmail.com>2017-12-18 12:50:41 +0100
committerIvan Topolnjak <ivantopo@gmail.com>2017-12-18 13:27:37 +0100
commita97c7dac0748732700d3a98ee44bd2fdf847ffbc (patch)
tree7e90436c56d59aea5c201d00614a1505ca88762b
parent72537e7a94d90131f8945cd78b6299e97e4cd027 (diff)
downloadKamon-a97c7dac0748732700d3a98ee44bd2fdf847ffbc.tar.gz
Kamon-a97c7dac0748732700d3a98ee44bd2fdf847ffbc.tar.bz2
Kamon-a97c7dac0748732700d3a98ee44bd2fdf847ffbc.zip
move alignment and duration utilities to the companion object
-rw-r--r--kamon-core-tests/src/test/scala/kamon/util/ClockSpec.scala39
-rw-r--r--kamon-core/src/main/scala/kamon/trace/Span.scala2
-rw-r--r--kamon-core/src/main/scala/kamon/util/Clock.scala28
3 files changed, 60 insertions, 9 deletions
diff --git a/kamon-core-tests/src/test/scala/kamon/util/ClockSpec.scala b/kamon-core-tests/src/test/scala/kamon/util/ClockSpec.scala
new file mode 100644
index 00000000..5f83d22c
--- /dev/null
+++ b/kamon-core-tests/src/test/scala/kamon/util/ClockSpec.scala
@@ -0,0 +1,39 @@
+package kamon.util
+
+import java.time.{Duration, Instant}
+
+import kamon.util
+import org.scalatest.{Matchers, WordSpec}
+
+class ClockSpec extends WordSpec with Matchers {
+ "the Clock" should {
+ "generate nanosecond precision Instants" in {
+ newClock().instant().getNano() % MicrosInSecond shouldNot be(0)
+ }
+
+ "turn Instants into micros" in {
+ Clock.toEpochMicros(Instant.parse("2017-12-18T08:39:59.000000000Z")) shouldBe 1513586399000000L
+ Clock.toEpochMicros(Instant.parse("2017-12-18T08:39:59.000000010Z")) shouldBe 1513586399000000L
+ Clock.toEpochMicros(Instant.parse("2017-12-18T08:39:59.987654321Z")) shouldBe 1513586399987654L
+ Clock.toEpochMicros(Instant.parse("2017-12-18T08:39:59.987000000Z")) shouldBe 1513586399987000L
+ }
+
+ "calculate nanos between two Instants" in {
+ Clock.nanosBetween(Instant.parse("2017-12-18T08:39:59.987654321Z"), Instant.parse("2017-12-18T08:39:59.987654322Z")) shouldBe 1
+ Clock.nanosBetween(Instant.parse("2017-12-18T08:39:59.987654322Z"), Instant.parse("2017-12-18T08:39:59.987654321Z")) shouldBe -1
+ Clock.nanosBetween(Instant.parse("2017-12-18T08:39:59.987Z"), Instant.parse("2017-12-18T08:39:59.988Z")) shouldBe 1000000
+ Clock.nanosBetween(Instant.parse("2017-12-18T08:39:59.987654Z"), Instant.parse("2017-12-18T08:39:59.987Z")) shouldBe -654000
+ }
+
+ "calculate ticks aligned to rounded boundaries" in {
+ Clock.nextTick(Instant.parse("2017-12-18T08:39:59.999Z"), Duration.ofSeconds(10)).toString shouldBe "2017-12-18T08:40:00Z"
+ Clock.nextTick(Instant.parse("2017-12-18T08:40:00.000Z"), Duration.ofSeconds(10)).toString shouldBe "2017-12-18T08:40:10Z"
+ Clock.nextTick(Instant.parse("2017-12-18T08:39:14.906Z"), Duration.ofSeconds(10)).toString shouldBe "2017-12-18T08:39:20Z"
+ }
+ }
+
+ val MicrosInSecond = 1000000
+
+ def newClock(): Clock =
+ new util.Clock.Default()
+}
diff --git a/kamon-core/src/main/scala/kamon/trace/Span.scala b/kamon-core/src/main/scala/kamon/trace/Span.scala
index d773d46e..690efeb4 100644
--- a/kamon-core/src/main/scala/kamon/trace/Span.scala
+++ b/kamon-core/src/main/scala/kamon/trace/Span.scala
@@ -201,7 +201,7 @@ object Span {
Span.FinishedSpan(spanContext, operationName, from, to, spanTags, marks)
private def recordSpanMetrics(to: Instant): Unit = {
- val elapsedTime = clock.nanosBetween(from, to)
+ val elapsedTime = Clock.nanosBetween(from, to)
val isErrorText = if(hasError) TagValue.True.text else TagValue.False.text
if(scopeSpanMetrics)
diff --git a/kamon-core/src/main/scala/kamon/util/Clock.scala b/kamon-core/src/main/scala/kamon/util/Clock.scala
index 48a88968..8c00ecc6 100644
--- a/kamon-core/src/main/scala/kamon/util/Clock.scala
+++ b/kamon-core/src/main/scala/kamon/util/Clock.scala
@@ -15,17 +15,17 @@
package kamon.util
-import java.time.{Instant, ZoneId, Clock => JavaClock}
+import java.time.{Duration, Instant, ZoneId, Clock => JavaClock}
abstract class Clock extends JavaClock {
def nanos(): Long
- def nanosBetween(left: Instant, right: Instant): Long
def toInstant(nanos: Long): Instant
}
object Clock {
private val MillisInSecond = 1000L
+ private val NanosInMicro = 1000L
private val MicrosInSecond = 1000000L
private val NanosInSecond = 1000000000L
@@ -74,16 +74,28 @@ object Clock {
override def instant(): Instant =
toInstant(System.nanoTime())
- override def nanosBetween(left: Instant, right: Instant): Long = {
- val secsDiff = Math.subtractExact(right.getEpochSecond, left.getEpochSecond)
- val totalNanos = Math.multiplyExact(secsDiff, NanosInSecond)
- return Math.addExact(totalNanos, right.getNano - left.getNano)
- }
-
override def withZone(zone: ZoneId): JavaClock =
systemClock.withZone(zone)
override def getZone: ZoneId =
systemClock.getZone()
}
+
+ def nanosBetween(left: Instant, right: Instant): Long = {
+ val secsDiff = Math.subtractExact(right.getEpochSecond, left.getEpochSecond)
+ val totalNanos = Math.multiplyExact(secsDiff, NanosInSecond)
+ return Math.addExact(totalNanos, right.getNano - left.getNano)
+ }
+
+ def toEpochMicros(instant: Instant): Long = {
+ Math.multiplyExact(instant.getEpochSecond, MicrosInSecond) + Math.floorDiv(instant.getNano, NanosInMicro)
+ }
+
+ def nextTick(from: Instant, expectedDuration: Duration): Instant = {
+ val fromMillis = from.toEpochMilli()
+ val intervalCount = Math.floorDiv(fromMillis, expectedDuration.toMillis)
+ val nextTickMillis = expectedDuration.toMillis * (intervalCount + 1)
+
+ Instant.ofEpochMilli(nextTickMillis)
+ }
} \ No newline at end of file