aboutsummaryrefslogtreecommitdiff
path: root/kamon-core/src/main/scala/kamon/util/Clock.scala
diff options
context:
space:
mode:
Diffstat (limited to 'kamon-core/src/main/scala/kamon/util/Clock.scala')
-rw-r--r--kamon-core/src/main/scala/kamon/util/Clock.scala59
1 files changed, 50 insertions, 9 deletions
diff --git a/kamon-core/src/main/scala/kamon/util/Clock.scala b/kamon-core/src/main/scala/kamon/util/Clock.scala
index 4f4561b5..48a88968 100644
--- a/kamon-core/src/main/scala/kamon/util/Clock.scala
+++ b/kamon-core/src/main/scala/kamon/util/Clock.scala
@@ -18,26 +18,67 @@ package kamon.util
import java.time.{Instant, ZoneId, Clock => JavaClock}
abstract class Clock extends JavaClock {
- def micros(): Long
- def relativeNanos(): Long
+ def nanos(): Long
+ def nanosBetween(left: Instant, right: Instant): Long
+ def toInstant(nanos: Long): Instant
}
object Clock {
+ private val MillisInSecond = 1000L
+ private val MicrosInSecond = 1000000L
+ private val NanosInSecond = 1000000000L
+
class Default extends Clock {
private val systemClock = JavaClock.systemUTC()
- private val startTimeMillis = System.currentTimeMillis()
- private val startNanoTime = System.nanoTime()
- private val startMicroTime = startTimeMillis * 1000L
+ private val (startTimeMillis, startNanoTime) = {
+ var calibrationIterations = 1000
+ var millis = System.currentTimeMillis()
+ var nanos = System.nanoTime()
+ var isCandidate = false
+
+ while(calibrationIterations > 0) {
+ val currentMillis = System.currentTimeMillis()
+ val currentNanos = System.nanoTime()
+
+ if(isCandidate && millis != currentMillis) {
+ millis = currentMillis
+ nanos = currentNanos
+ calibrationIterations = 0
+ } else {
+ if(millis == currentMillis) {
+ isCandidate = true
+ } else {
+ millis = currentMillis
+ nanos = currentNanos
+ }
+ }
+
+ calibrationIterations -= 1
+ }
- override def micros(): Long =
- startMicroTime + ((System.nanoTime() - startNanoTime) / 1000L)
+ (millis, nanos)
+ }
- override def relativeNanos(): Long =
+ private val startSecondTime = Math.floorDiv(startTimeMillis, MillisInSecond)
+ private val startSecondNanoOffset = Math.multiplyExact(Math.floorMod(startTimeMillis, MillisInSecond), MicrosInSecond)
+
+ override def nanos(): Long =
System.nanoTime()
+ override def toInstant(nanos: Long): Instant = {
+ val nanoOffset = nanos - startNanoTime + startSecondNanoOffset
+ Instant.ofEpochSecond(startSecondTime, nanoOffset)
+ }
+
override def instant(): Instant =
- systemClock.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)