diff options
author | Ivan Topolnjak <ivantopo@gmail.com> | 2017-12-13 23:32:30 +0100 |
---|---|---|
committer | Ivan Topolnjak <ivantopo@gmail.com> | 2017-12-14 00:05:55 +0100 |
commit | 622c8d12735c1a8de3716984686e52bc33368004 (patch) | |
tree | 6665d553b6fbea36391e7eb4b25f2fbfc4526f58 /kamon-core | |
parent | 4a2d29852c8fc558ae1eaf61a25bde5a0bc161bc (diff) | |
download | Kamon-622c8d12735c1a8de3716984686e52bc33368004.tar.gz Kamon-622c8d12735c1a8de3716984686e52bc33368004.tar.bz2 Kamon-622c8d12735c1a8de3716984686e52bc33368004.zip |
use java.time.Instant with nanoseconds precision in the Tracer
Diffstat (limited to 'kamon-core')
-rw-r--r-- | kamon-core/src/main/scala/kamon/trace/Span.scala | 59 | ||||
-rw-r--r-- | kamon-core/src/main/scala/kamon/trace/Tracer.scala | 12 | ||||
-rw-r--r-- | kamon-core/src/main/scala/kamon/util/Clock.scala | 59 |
3 files changed, 84 insertions, 46 deletions
diff --git a/kamon-core/src/main/scala/kamon/trace/Span.scala b/kamon-core/src/main/scala/kamon/trace/Span.scala index 545a3f64..d773d46e 100644 --- a/kamon-core/src/main/scala/kamon/trace/Span.scala +++ b/kamon-core/src/main/scala/kamon/trace/Span.scala @@ -16,6 +16,8 @@ package kamon package trace +import java.time.Instant + import kamon.ReporterRegistry.SpanSink import kamon.context.Key import kamon.metric.MeasurementUnit @@ -43,7 +45,7 @@ sealed abstract class Span { def mark(key: String): Span - def mark(timestampMicros: Long, key: String): Span + def mark(at: Instant, key: String): Span def addError(error: String): Span @@ -55,7 +57,7 @@ sealed abstract class Span { def disableMetrics(): Span - def finish(finishTimestampMicros: Long): Unit + def finish(at: Instant): Unit def finish(): Unit } @@ -73,26 +75,19 @@ object Span { override def tag(key: String, value: Boolean): Span = this override def tagMetric(key: String, value: String): Span = this override def mark(key: String): Span = this - override def mark(timestampMicros: Long, key: String): Span = this + override def mark(at: Instant, key: String): Span = this override def addError(error: String): Span = this override def addError(error: String, throwable: Throwable): Span = this override def setOperationName(name: String): Span = this override def enableMetrics(): Span = this override def disableMetrics(): Span = this override def finish(): Unit = {} - override def finish(finishTimestampMicros: Long): Unit = {} + override def finish(at: Instant): Unit = {} } - /** - * - * @param spanContext - * @param initialOperationName - * @param initialSpanTags - * @param startTimestampMicros - * @param spanSink - */ + final class Local(spanContext: SpanContext, parent: Option[Span], initialOperationName: String, initialSpanTags: Map[String, Span.TagValue], - initialMetricTags: Map[String, String], startTimestampMicros: Long, spanSink: SpanSink, trackMetrics: Boolean, scopeSpanMetrics: Boolean, clock: Clock) extends Span { + initialMetricTags: Map[String, String], from: Instant, spanSink: SpanSink, trackMetrics: Boolean, scopeSpanMetrics: Boolean, clock: Clock) extends Span { private var collectMetrics: Boolean = trackMetrics private var open: Boolean = true @@ -138,11 +133,11 @@ object Span { } override def mark(key: String): Span = { - mark(clock.micros(), key) + mark(clock.instant(), key) } - override def mark(timestampMicros: Long, key: String): Span = synchronized { - this.marks = Mark(timestampMicros, key) :: this.marks + override def mark(at: Instant, key: String): Span = synchronized { + this.marks = Mark(at, key) :: this.marks this } @@ -188,25 +183,25 @@ object Span { } override def finish(): Unit = - finish(clock.micros()) + finish(clock.instant()) - override def finish(finishMicros: Long): Unit = synchronized { + override def finish(to: Instant): Unit = synchronized { if (open) { open = false if(collectMetrics) - recordSpanMetrics(finishMicros) + recordSpanMetrics(to) if(sampled) - spanSink.reportSpan(toFinishedSpan(finishMicros)) + spanSink.reportSpan(toFinishedSpan(to)) } } - private def toFinishedSpan(endTimestampMicros: Long): Span.FinishedSpan = - Span.FinishedSpan(spanContext, operationName, startTimestampMicros, endTimestampMicros, spanTags, marks) + private def toFinishedSpan(to: Instant): Span.FinishedSpan = + Span.FinishedSpan(spanContext, operationName, from, to, spanTags, marks) - private def recordSpanMetrics(endTimestampMicros: Long): Unit = { - val elapsedTime = endTimestampMicros - startTimestampMicros + private def recordSpanMetrics(to: Instant): Unit = { + val elapsedTime = clock.nanosBetween(from, to) val isErrorText = if(hasError) TagValue.True.text else TagValue.False.text if(scopeSpanMetrics) @@ -223,9 +218,9 @@ object Span { object Local { def apply(spanContext: SpanContext, parent: Option[Span], initialOperationName: String, initialSpanTags: Map[String, Span.TagValue], - initialMetricTags: Map[String, String], startTimestampMicros: Long, spanSink: SpanSink, + initialMetricTags: Map[String, String], from: Instant, spanSink: SpanSink, trackMetrics: Boolean, scopeSpanMetrics: Boolean, clock: Clock): Local = - new Local(spanContext, parent, initialOperationName, initialSpanTags, initialMetricTags, startTimestampMicros, spanSink, trackMetrics, scopeSpanMetrics, clock) + new Local(spanContext, parent, initialOperationName, initialSpanTags, initialMetricTags, from, spanSink, trackMetrics, scopeSpanMetrics, clock) } @@ -237,14 +232,14 @@ object Span { override def tag(key: String, value: Boolean): Span = this override def tagMetric(key: String, value: String): Span = this override def mark(key: String): Span = this - override def mark(timestampMicros: Long, key: String): Span = this + override def mark(at: Instant, key: String): Span = this override def addError(error: String): Span = this override def addError(error: String, throwable: Throwable): Span = this override def setOperationName(name: String): Span = this override def enableMetrics(): Span = this override def disableMetrics(): Span = this override def finish(): Unit = {} - override def finish(finishTimestampMicros: Long): Unit = {} + override def finish(at: Instant): Unit = {} } object Remote { @@ -273,17 +268,17 @@ object Span { object Metrics { - val ProcessingTime = Kamon.histogram("span.processing-time", MeasurementUnit.time.microseconds) + val ProcessingTime = Kamon.histogram("span.processing-time", MeasurementUnit.time.nanoseconds) val SpanErrorCount = Kamon.counter("span.error-count") } - case class Mark(timestampMicros: Long, key: String) + case class Mark(instant: Instant, key: String) case class FinishedSpan( context: SpanContext, operationName: String, - startTimestampMicros: Long, - endTimestampMicros: Long, + from: Instant, + to: Instant, tags: Map[String, Span.TagValue], marks: Seq[Span.Mark] ) diff --git a/kamon-core/src/main/scala/kamon/trace/Tracer.scala b/kamon-core/src/main/scala/kamon/trace/Tracer.scala index 4950a700..3e857f00 100644 --- a/kamon-core/src/main/scala/kamon/trace/Tracer.scala +++ b/kamon-core/src/main/scala/kamon/trace/Tracer.scala @@ -15,6 +15,8 @@ package kamon.trace +import java.time.Instant + import com.typesafe.config.Config import kamon.ReporterRegistry.SpanSink import kamon.Kamon @@ -92,7 +94,7 @@ object Tracer { final class SpanBuilder(operationName: String, tracer: Tracer.Default, spanSink: SpanSink, clock: Clock) { private var parentSpan: Span = _ private var initialOperationName: String = operationName - private var startTimestamp = 0L + private var from: Instant = Instant.EPOCH private var initialSpanTags = Map.empty[String, Span.TagValue] private var initialMetricTags = Map.empty[String, String] private var useParentFromContext = true @@ -125,8 +127,8 @@ object Tracer { this } - def withStartTimestamp(microseconds: Long): SpanBuilder = { - this.startTimestamp = microseconds + def withFrom(from: Instant): SpanBuilder = { + this.from = from this } @@ -158,7 +160,7 @@ object Tracer { def start(): Span = { - val startTimestampMicros = if(startTimestamp != 0L) startTimestamp else clock.micros() + val spanFrom = if(from == Instant.EPOCH) clock.instant() else from val parentSpan: Option[Span] = Option(this.parentSpan) .orElse(if(useParentFromContext) Some(Kamon.currentContext().get(Span.ContextKey)) else None) @@ -183,7 +185,7 @@ object Tracer { initialOperationName, initialSpanTags, initialMetricTags, - startTimestampMicros, + spanFrom, spanSink, trackMetrics, tracer.scopeSpanMetrics, 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) |