aboutsummaryrefslogtreecommitdiff
path: root/kamon-core/src/main/scala/kamon/trace/TraceContext.scala
diff options
context:
space:
mode:
Diffstat (limited to 'kamon-core/src/main/scala/kamon/trace/TraceContext.scala')
-rw-r--r--kamon-core/src/main/scala/kamon/trace/TraceContext.scala207
1 files changed, 117 insertions, 90 deletions
diff --git a/kamon-core/src/main/scala/kamon/trace/TraceContext.scala b/kamon-core/src/main/scala/kamon/trace/TraceContext.scala
index 64ee70be..c4c28a68 100644
--- a/kamon-core/src/main/scala/kamon/trace/TraceContext.scala
+++ b/kamon-core/src/main/scala/kamon/trace/TraceContext.scala
@@ -23,113 +23,73 @@ import kamon.Kamon
import kamon.metric._
import java.util.concurrent.ConcurrentLinkedQueue
import kamon.trace.TraceContextAware.DefaultTraceContextAware
-import kamon.trace.TraceContext.SegmentIdentity
import kamon.metric.TraceMetrics.TraceMetricRecorder
import scala.annotation.tailrec
-trait TraceContext {
+sealed trait TraceContext {
def name: String
def token: String
- def system: ActorSystem
def rename(name: String): Unit
- def levelOfDetail: TracingLevelOfDetail
- def startSegment(identity: SegmentIdentity, metadata: Map[String, String]): SegmentCompletionHandle
- def finish(metadata: Map[String, String])
+ def finish(): Unit
def origin: TraceContextOrigin
- def startMilliTime: Long
def isOpen: Boolean
-
- private[kamon] val traceLocalStorage: TraceLocalStorage = new TraceLocalStorage
-}
-
-object TraceContext {
- type SegmentIdentity = MetricIdentity
-}
-
-trait SegmentCompletionHandle {
- def finish(metadata: Map[String, String] = Map.empty)
-}
-
-case class SegmentData(identity: MetricIdentity, duration: Long, metadata: Map[String, String])
-
-sealed trait TracingLevelOfDetail
-case object OnlyMetrics extends TracingLevelOfDetail
-case object SimpleTrace extends TracingLevelOfDetail
-case object FullTrace extends TracingLevelOfDetail
-
-sealed trait TraceContextOrigin
-object TraceContextOrigin {
- case object Local extends TraceContextOrigin
- case object Remote extends TraceContextOrigin
+ def isEmpty: Boolean
+ def nonEmpty: Boolean = !isEmpty
+ def startSegment(segmentName: String, label: String): Segment
+ def nanoTimestamp: Long
}
-trait TraceContextAware extends Serializable {
- def captureNanoTime: Long
- def traceContext: Option[TraceContext]
+sealed trait Segment {
+ def name: String
+ def rename(newName: String): Unit
+ def label: String
+ def finish(): Unit
+ def isEmpty: Boolean
}
-object TraceContextAware {
- def default: TraceContextAware = new DefaultTraceContextAware
-
- class DefaultTraceContextAware extends TraceContextAware {
- @transient val captureNanoTime = System.nanoTime()
- @transient val traceContext = TraceRecorder.currentContext
-
- //
- // Beware of this hack, it might bite us in the future!
- //
- // When using remoting/cluster all messages carry the TraceContext in the envelope in which they
- // are sent but that doesn't apply to System Messages. We are certain that the TraceContext is
- // available (if any) when the system messages are read and this will make sure that it is correctly
- // captured and propagated.
- @throws[ObjectStreamException]
- private def readResolve: AnyRef = {
- new DefaultTraceContextAware
- }
+case object EmptyTraceContext extends TraceContext {
+ def name: String = "empty-trace"
+ def token: String = ""
+ def rename(name: String): Unit = {}
+ def finish(): Unit = {}
+ def origin: TraceContextOrigin = TraceContextOrigin.Local
+ def isOpen: Boolean = false
+ def isEmpty: Boolean = true
+ def startSegment(segmentName: String, label: String): Segment = EmptySegment
+ def nanoTimestamp: Long = 0L
+
+ case object EmptySegment extends Segment {
+ val name: String = "empty-segment"
+ val label: String = "empty-label"
+ def isEmpty: Boolean = true
+ def rename(newName: String): Unit = {}
+ def finish: Unit = {}
}
}
-trait SegmentCompletionHandleAware extends TraceContextAware {
- @volatile var segmentCompletionHandle: Option[SegmentCompletionHandle] = None
-}
-
-object SegmentCompletionHandleAware {
- def default: SegmentCompletionHandleAware = new DefaultSegmentCompletionHandleAware
-
- class DefaultSegmentCompletionHandleAware extends DefaultTraceContextAware with SegmentCompletionHandleAware {}
-}
-
-class SimpleMetricCollectionContext(traceName: String, val token: String, metadata: Map[String, String],
- val origin: TraceContextOrigin, val system: ActorSystem, val startMilliTime: Long = System.currentTimeMillis,
- izOpen: Boolean = true) extends TraceContext {
+class DefaultTraceContext(traceName: String, val token: String, izOpen: Boolean, val levelOfDetail: LevelOfDetail,
+ val origin: TraceContextOrigin, nanoTimeztamp: Long, val system: ActorSystem) extends TraceContext {
+ val isEmpty: Boolean = false
@volatile private var _name = traceName
@volatile private var _isOpen = izOpen
- val levelOfDetail = OnlyMetrics
- val startNanoTime = System.nanoTime()
- val finishedSegments = new ConcurrentLinkedQueue[SegmentData]()
- val metricsExtension = Kamon(Metrics)(system)
+ private val _nanoTimestamp = nanoTimeztamp
+ private val finishedSegments = new ConcurrentLinkedQueue[SegmentData]()
+ private val metricsExtension = Kamon(Metrics)(system)
+ private[kamon] val traceLocalStorage: TraceLocalStorage = new TraceLocalStorage
def name: String = _name
+ def rename(newName: String): Unit =
+ if (isOpen) _name = newName // TODO: log a warning about renaming a closed trace.
- def rename(newName: String): Unit = _name = newName
-
- def isOpen(): Boolean = _isOpen
+ def isOpen: Boolean = _isOpen
+ def nanoTimestamp: Long = _nanoTimestamp
- def finish(metadata: Map[String, String]): Unit = {
+ def finish(): Unit = {
_isOpen = false
-
- val elapsedNanoTime =
- if (origin == TraceContextOrigin.Local)
- // Everything is local, nanoTime is still the best resolution we can use.
- System.nanoTime() - startNanoTime
- else
- // For a remote TraceContext we can only rely on the startMilliTime and we need to scale it to nanoseconds
- // to be consistent with unit used for all latency measurements.
- (System.currentTimeMillis() - startMilliTime) * 1000000L
-
+ val elapsedNanoTime = System.nanoTime() - _nanoTimestamp
val metricRecorder = metricsExtension.register(TraceMetrics(name), TraceMetrics.Factory)
metricRecorder.map { traceMetrics ⇒
@@ -138,6 +98,8 @@ class SimpleMetricCollectionContext(traceName: String, val token: String, metada
}
}
+ def startSegment(segmentName: String, segmentLabel: String): Segment = new DefaultSegment(segmentName, segmentLabel)
+
@tailrec private def drainFinishedSegments(metricRecorder: TraceMetricRecorder): Unit = {
val segment = finishedSegments.poll()
if (segment != null) {
@@ -146,8 +108,8 @@ class SimpleMetricCollectionContext(traceName: String, val token: String, metada
}
}
- private def finishSegment(identity: MetricIdentity, duration: Long, metadata: Map[String, String]): Unit = {
- finishedSegments.add(SegmentData(identity, duration, metadata))
+ private def finishSegment(segmentName: String, label: String, duration: Long): Unit = {
+ finishedSegments.add(SegmentData(SegmentMetricIdentity(segmentName, label), duration))
if (!_isOpen) {
metricsExtension.register(TraceMetrics(name), TraceMetrics.Factory).map { traceMetrics ⇒
@@ -156,16 +118,81 @@ class SimpleMetricCollectionContext(traceName: String, val token: String, metada
}
}
- def startSegment(identity: SegmentIdentity, metadata: Map[String, String]): SegmentCompletionHandle =
- new SimpleMetricCollectionCompletionHandle(identity, metadata)
+ class DefaultSegment(segmentName: String, val label: String) extends Segment {
+ private val _segmentStartNanoTime = System.nanoTime()
+ @volatile private var _segmentName = segmentName
+ @volatile private var _isOpen = true
- class SimpleMetricCollectionCompletionHandle(identity: MetricIdentity, startMetadata: Map[String, String]) extends SegmentCompletionHandle {
- val segmentStartNanoTime = System.nanoTime()
+ def name: String = _segmentName
+ def rename(newName: String): Unit = _segmentName = newName
+ def isEmpty: Boolean = false
- def finish(metadata: Map[String, String] = Map.empty): Unit = {
+ def finish: Unit = {
val segmentFinishNanoTime = System.nanoTime()
- finishSegment(identity, (segmentFinishNanoTime - segmentStartNanoTime), startMetadata ++ metadata)
+ finishSegment(name, label, (segmentFinishNanoTime - _segmentStartNanoTime))
+ }
+ }
+}
+
+case class SegmentMetricIdentity(name: String, label: String) extends MetricIdentity
+case class SegmentData(identity: SegmentMetricIdentity, duration: Long)
+
+object SegmentMetricIdentityLabel {
+ val HttpClient = "http-client"
+}
+
+sealed trait LevelOfDetail
+object LevelOfDetail {
+ case object OnlyMetrics extends LevelOfDetail
+ case object SimpleTrace extends LevelOfDetail
+ case object FullTrace extends LevelOfDetail
+}
+
+sealed trait TraceContextOrigin
+object TraceContextOrigin {
+ case object Local extends TraceContextOrigin
+ case object Remote extends TraceContextOrigin
+}
+
+trait TraceContextAware extends Serializable {
+ def traceContext: TraceContext
+}
+
+object TraceContextAware {
+ def default: TraceContextAware = new DefaultTraceContextAware
+
+ class DefaultTraceContextAware extends TraceContextAware {
+ @transient val traceContext = TraceRecorder.currentContext
+
+ //
+ // Beware of this hack, it might bite us in the future!
+ //
+ // When using remoting/cluster all messages carry the TraceContext in the envelope in which they
+ // are sent but that doesn't apply to System Messages. We are certain that the TraceContext is
+ // available (if any) when the system messages are read and this will make sure that it is correctly
+ // captured and propagated.
+ @throws[ObjectStreamException]
+ private def readResolve: AnyRef = {
+ new DefaultTraceContextAware
}
}
}
+trait TimestampedTraceContextAware extends TraceContextAware {
+ def captureNanoTime: Long
+}
+
+object TimestampedTraceContextAware {
+ def default: TimestampedTraceContextAware = new DefaultTraceContextAware with TimestampedTraceContextAware {
+ @transient val captureNanoTime = System.nanoTime()
+ }
+}
+
+trait SegmentAware {
+ @volatile var segment: Segment = EmptyTraceContext.EmptySegment
+}
+
+object SegmentAware {
+ def default: SegmentAware = new DefaultSegmentAware
+ class DefaultSegmentAware extends DefaultTraceContextAware with SegmentAware {}
+} \ No newline at end of file