aboutsummaryrefslogtreecommitdiff
path: root/kamon-core/src/main/scala/kamon/trace
diff options
context:
space:
mode:
Diffstat (limited to 'kamon-core/src/main/scala/kamon/trace')
-rw-r--r--kamon-core/src/main/scala/kamon/trace/Incubator.scala2
-rw-r--r--kamon-core/src/main/scala/kamon/trace/MetricsOnlyContext.scala37
-rw-r--r--kamon-core/src/main/scala/kamon/trace/Sampler.scala3
-rw-r--r--kamon-core/src/main/scala/kamon/trace/TraceContext.scala66
-rw-r--r--kamon-core/src/main/scala/kamon/trace/TraceExtension.scala91
-rw-r--r--kamon-core/src/main/scala/kamon/trace/TraceLocal.scala4
-rw-r--r--kamon-core/src/main/scala/kamon/trace/TraceRecorder.scala79
-rw-r--r--kamon-core/src/main/scala/kamon/trace/TracerExtension.scala94
-rw-r--r--kamon-core/src/main/scala/kamon/trace/TracerExtensionSettings.scala30
-rw-r--r--kamon-core/src/main/scala/kamon/trace/TracingContext.scala13
-rw-r--r--kamon-core/src/main/scala/kamon/trace/logging/LogbackTraceTokenConverter.scala4
-rw-r--r--kamon-core/src/main/scala/kamon/trace/logging/MdcKeysSupport.scala4
12 files changed, 208 insertions, 219 deletions
diff --git a/kamon-core/src/main/scala/kamon/trace/Incubator.scala b/kamon-core/src/main/scala/kamon/trace/Incubator.scala
index c39a9984..3b2a3bf9 100644
--- a/kamon-core/src/main/scala/kamon/trace/Incubator.scala
+++ b/kamon-core/src/main/scala/kamon/trace/Incubator.scala
@@ -19,8 +19,8 @@ package kamon.trace
import java.util.concurrent.TimeUnit
import akka.actor.{ ActorLogging, Props, Actor, ActorRef }
-import kamon.{ NanoInterval, RelativeNanoTimestamp }
import kamon.trace.Incubator.{ CheckForCompletedTraces, IncubatingTrace }
+import kamon.util.{ NanoInterval, RelativeNanoTimestamp }
import scala.annotation.tailrec
import scala.collection.immutable.Queue
import scala.concurrent.duration._
diff --git a/kamon-core/src/main/scala/kamon/trace/MetricsOnlyContext.scala b/kamon-core/src/main/scala/kamon/trace/MetricsOnlyContext.scala
index 66c6633d..e62178dd 100644
--- a/kamon-core/src/main/scala/kamon/trace/MetricsOnlyContext.scala
+++ b/kamon-core/src/main/scala/kamon/trace/MetricsOnlyContext.scala
@@ -18,16 +18,16 @@ package kamon.trace
import java.util.concurrent.ConcurrentLinkedQueue
-import akka.actor.ActorSystem
+import akka.actor.{ ExtensionId, ActorSystem }
import akka.event.LoggingAdapter
-import kamon.{ RelativeNanoTimestamp, NanoInterval }
-import kamon.metric.TraceMetrics.TraceMetricRecorder
+import kamon.Kamon.Extension
import kamon.metric.{ MetricsExtension, TraceMetrics }
+import kamon.util.{ NanoInterval, RelativeNanoTimestamp }
import scala.annotation.tailrec
-private[trace] class MetricsOnlyContext(traceName: String, val token: String, izOpen: Boolean, val levelOfDetail: LevelOfDetail, val origin: TraceContextOrigin,
- val startRelativeTimestamp: RelativeNanoTimestamp, log: LoggingAdapter, metricsExtension: MetricsExtension, val system: ActorSystem)
+private[kamon] class MetricsOnlyContext(traceName: String, val token: String, izOpen: Boolean, val levelOfDetail: LevelOfDetail,
+ val startTimestamp: RelativeNanoTimestamp, log: LoggingAdapter, metricsExtension: MetricsExtension, val actorSystem: ActorSystem)
extends TraceContext {
@volatile private var _name = traceName
@@ -48,35 +48,36 @@ private[trace] class MetricsOnlyContext(traceName: String, val token: String, iz
def isOpen: Boolean = _isOpen
def addMetadata(key: String, value: String): Unit = {}
+ def lookupExtension[T <: Extension](id: ExtensionId[T]): T = id(actorSystem)
+
def finish(): Unit = {
_isOpen = false
- val traceElapsedTime = NanoInterval.since(startRelativeTimestamp)
+ val traceElapsedTime = NanoInterval.since(startTimestamp)
_elapsedTime = traceElapsedTime
- val metricRecorder = metricsExtension.register(TraceMetrics(name), TraceMetrics.Factory)
- metricRecorder.map { traceMetrics ⇒
- traceMetrics.elapsedTime.record(traceElapsedTime.nanos)
- drainFinishedSegments(traceMetrics)
+ metricsExtension.register(TraceMetrics, name).map { registration ⇒
+ registration.recorder.ElapsedTime.record(traceElapsedTime.nanos)
+ drainFinishedSegments(registration.recorder)
}
}
def startSegment(segmentName: String, category: String, library: String): Segment =
new MetricsOnlySegment(segmentName, category, library)
- @tailrec private def drainFinishedSegments(metricRecorder: TraceMetricRecorder): Unit = {
+ @tailrec private def drainFinishedSegments(recorder: TraceMetrics): Unit = {
val segment = _finishedSegments.poll()
if (segment != null) {
- metricRecorder.segmentRecorder(segment.identity).record(segment.duration.nanos)
- drainFinishedSegments(metricRecorder)
+ recorder.segment(segment.name, segment.category, segment.library).record(segment.duration.nanos)
+ drainFinishedSegments(recorder)
}
}
protected def finishSegment(segmentName: String, category: String, library: String, duration: NanoInterval): Unit = {
- _finishedSegments.add(SegmentLatencyData(SegmentMetricIdentity(segmentName, category, library), duration))
+ _finishedSegments.add(SegmentLatencyData(segmentName, category, library, duration))
if (isClosed) {
- metricsExtension.register(TraceMetrics(name), TraceMetrics.Factory).map { traceMetrics ⇒
- drainFinishedSegments(traceMetrics)
+ metricsExtension.register(TraceMetrics, name).map { registration ⇒
+ drainFinishedSegments(registration.recorder)
}
}
}
@@ -118,4 +119,6 @@ private[trace] class MetricsOnlyContext(traceName: String, val token: String, iz
def elapsedTime: NanoInterval = _elapsedTime
def startTimestamp: RelativeNanoTimestamp = _startTimestamp
}
-} \ No newline at end of file
+}
+
+case class SegmentLatencyData(name: String, category: String, library: String, duration: NanoInterval)
diff --git a/kamon-core/src/main/scala/kamon/trace/Sampler.scala b/kamon-core/src/main/scala/kamon/trace/Sampler.scala
index 2308d1d0..5abba221 100644
--- a/kamon-core/src/main/scala/kamon/trace/Sampler.scala
+++ b/kamon-core/src/main/scala/kamon/trace/Sampler.scala
@@ -16,8 +16,7 @@
package kamon.trace
-import kamon.NanoInterval
-import kamon.util.Sequencer
+import kamon.util.{ NanoInterval, Sequencer }
import scala.concurrent.forkjoin.ThreadLocalRandom
trait Sampler {
diff --git a/kamon-core/src/main/scala/kamon/trace/TraceContext.scala b/kamon-core/src/main/scala/kamon/trace/TraceContext.scala
index 60244eaa..ed8170a9 100644
--- a/kamon-core/src/main/scala/kamon/trace/TraceContext.scala
+++ b/kamon-core/src/main/scala/kamon/trace/TraceContext.scala
@@ -17,26 +17,60 @@
package kamon.trace
import java.io.ObjectStreamException
-import akka.actor.ActorSystem
+import akka.actor.{ ExtensionId, ActorSystem }
+import kamon.Kamon.Extension
import kamon._
import kamon.metric._
import kamon.trace.TraceContextAware.DefaultTraceContextAware
+import kamon.util.{ NanoInterval, RelativeNanoTimestamp }
trait TraceContext {
def name: String
def token: String
- def origin: TraceContextOrigin
def isEmpty: Boolean
def nonEmpty: Boolean = !isEmpty
def isOpen: Boolean
def isClosed: Boolean = !isOpen
- def system: ActorSystem
def finish(): Unit
def rename(newName: String): Unit
+
def startSegment(segmentName: String, category: String, library: String): Segment
def addMetadata(key: String, value: String)
- def startRelativeTimestamp: RelativeNanoTimestamp
+
+ def startTimestamp: RelativeNanoTimestamp
+
+ def lookupExtension[T <: Kamon.Extension](id: ExtensionId[T]): T
+}
+
+object TraceContext {
+ private[kamon] val _traceContextStorage = new ThreadLocal[TraceContext] {
+ override def initialValue(): TraceContext = EmptyTraceContext
+ }
+
+ def currentContext: TraceContext =
+ _traceContextStorage.get()
+
+ def setCurrentContext(context: TraceContext): Unit =
+ _traceContextStorage.set(context)
+
+ def clearCurrentContext: Unit =
+ _traceContextStorage.remove()
+
+ def withContext[T](context: TraceContext)(code: ⇒ T): T = {
+ val oldContext = _traceContextStorage.get()
+ _traceContextStorage.set(context)
+
+ try code finally _traceContextStorage.set(oldContext)
+ }
+
+ def map[T](f: TraceContext ⇒ T): Option[T] = {
+ val current = currentContext
+ if (current.nonEmpty)
+ Some(f(current))
+ else None
+ }
+
}
trait Segment {
@@ -56,16 +90,17 @@ trait Segment {
case object EmptyTraceContext extends TraceContext {
def name: String = "empty-trace"
def token: String = ""
- def origin: TraceContextOrigin = TraceContextOrigin.Local
def isEmpty: Boolean = true
def isOpen: Boolean = false
- def system: ActorSystem = sys.error("Can't obtain a ActorSystem from a EmptyTraceContext.")
def finish(): Unit = {}
def rename(name: String): Unit = {}
def startSegment(segmentName: String, category: String, library: String): Segment = EmptySegment
def addMetadata(key: String, value: String): Unit = {}
- def startRelativeTimestamp = new RelativeNanoTimestamp(0L)
+ def startTimestamp = new RelativeNanoTimestamp(0L)
+
+ override def lookupExtension[T <: Extension](id: ExtensionId[T]): T =
+ sys.error("Can't lookup extensions on a EmptyTraceContext.")
case object EmptySegment extends Segment {
val name: String = "empty-segment"
@@ -80,14 +115,17 @@ case object EmptyTraceContext extends TraceContext {
}
}
-case class SegmentMetricIdentity(name: String, category: String, library: String) extends MetricIdentity
-case class SegmentLatencyData(identity: SegmentMetricIdentity, duration: NanoInterval)
-
object SegmentCategory {
val HttpClient = "http-client"
val Database = "database"
}
+class LOD private[trace] (val level: Int) extends AnyVal
+object LOD {
+ val MetricsOnly = new LOD(1)
+ val SimpleTrace = new LOD(2)
+}
+
sealed trait LevelOfDetail
object LevelOfDetail {
case object MetricsOnly extends LevelOfDetail
@@ -95,12 +133,6 @@ object 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
}
@@ -109,7 +141,7 @@ object TraceContextAware {
def default: TraceContextAware = new DefaultTraceContextAware
class DefaultTraceContextAware extends TraceContextAware {
- @transient val traceContext = TraceRecorder.currentContext
+ @transient val traceContext = TraceContext.currentContext
//
// Beware of this hack, it might bite us in the future!
diff --git a/kamon-core/src/main/scala/kamon/trace/TraceExtension.scala b/kamon-core/src/main/scala/kamon/trace/TraceExtension.scala
deleted file mode 100644
index 41f022d0..00000000
--- a/kamon-core/src/main/scala/kamon/trace/TraceExtension.scala
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-
-package kamon.trace
-
-import java.util.concurrent.TimeUnit
-
-import akka.actor._
-import akka.actor
-import akka.event.Logging
-import kamon._
-import kamon.metric.Metrics
-import kamon.util.GlobPathFilter
-
-class TraceExtension(system: ExtendedActorSystem) extends Kamon.Extension {
- val config = system.settings.config.getConfig("kamon.trace")
- val dispatcher = system.dispatchers.lookup(config.getString("dispatcher"))
-
- val detailLevel: LevelOfDetail = config.getString("level") match {
- case "metrics-only" ⇒ LevelOfDetail.MetricsOnly
- case "simple-trace" ⇒ LevelOfDetail.SimpleTrace
- case other ⇒ sys.error(s"Unknown tracing level $other present in the configuration file.")
- }
-
- val sampler: Sampler =
- if (detailLevel == LevelOfDetail.MetricsOnly) NoSampling
- else config.getString("sampling") match {
- case "all" ⇒ SampleAll
- case "random" ⇒ new RandomSampler(config.getInt("random-sampler.chance"))
- case "ordered" ⇒ new OrderedSampler(config.getInt("ordered-sampler.interval"))
- case "threshold" ⇒ new ThresholdSampler(config.getDuration("threshold-sampler.minimum-elapsed-time", TimeUnit.NANOSECONDS))
- }
-
- val log = Logging(system, "TraceExtension")
- val subscriptions = system.actorOf(Props[TraceSubscriptions], "trace-subscriptions")
- val incubator = system.actorOf(Incubator.props(subscriptions))
- val metricsExtension = Kamon(Metrics)(system)
-
- def newTraceContext(traceName: String, token: String, origin: TraceContextOrigin, system: ActorSystem): TraceContext =
- newTraceContext(traceName, token, true, origin, RelativeNanoTimestamp.now, system)
-
- def newTraceContext(traceName: String, token: String, isOpen: Boolean, origin: TraceContextOrigin,
- startTimestamp: RelativeNanoTimestamp, system: ActorSystem): TraceContext = {
- def newMetricsOnlyContext = new MetricsOnlyContext(traceName, token, isOpen, detailLevel, origin, startTimestamp, log, metricsExtension, system)
-
- if (detailLevel == LevelOfDetail.MetricsOnly || origin == TraceContextOrigin.Remote)
- newMetricsOnlyContext
- else {
- if (!sampler.shouldTrace)
- newMetricsOnlyContext
- else
- new TracingContext(traceName, token, true, detailLevel, origin, startTimestamp, log, metricsExtension, this, system)
- }
- }
-
- def subscribe(subscriber: ActorRef): Unit = subscriptions ! TraceSubscriptions.Subscribe(subscriber)
- def unsubscribe(subscriber: ActorRef): Unit = subscriptions ! TraceSubscriptions.Unsubscribe(subscriber)
-
- private[kamon] def dispatchTracingContext(trace: TracingContext): Unit =
- if (sampler.shouldReport(trace.elapsedTime))
- if (trace.shouldIncubate)
- incubator ! trace
- else
- subscriptions ! trace.generateTraceInfo
-
-}
-
-object Trace extends ExtensionId[TraceExtension] with ExtensionIdProvider {
- def lookup(): ExtensionId[_ <: actor.Extension] = Trace
- def createExtension(system: ExtendedActorSystem): TraceExtension = new TraceExtension(system)
-
- case class MetricGroupFilter(includes: List[GlobPathFilter], excludes: List[GlobPathFilter]) {
- def accept(name: String): Boolean = includes.exists(_.accept(name)) && !excludes.exists(_.accept(name))
- }
-}
-
-case class TraceInfo(name: String, token: String, timestamp: NanoTimestamp, elapsedTime: NanoInterval, metadata: Map[String, String], segments: List[SegmentInfo])
-case class SegmentInfo(name: String, category: String, library: String, timestamp: NanoTimestamp, elapsedTime: NanoInterval, metadata: Map[String, String]) \ No newline at end of file
diff --git a/kamon-core/src/main/scala/kamon/trace/TraceLocal.scala b/kamon-core/src/main/scala/kamon/trace/TraceLocal.scala
index 84e234f3..057f564e 100644
--- a/kamon-core/src/main/scala/kamon/trace/TraceLocal.scala
+++ b/kamon-core/src/main/scala/kamon/trace/TraceLocal.scala
@@ -42,12 +42,12 @@ object TraceLocal {
object HttpContextKey extends TraceLocal.TraceLocalKey { type ValueType = HttpContext }
- def store(key: TraceLocalKey)(value: key.ValueType): Unit = TraceRecorder.currentContext match {
+ def store(key: TraceLocalKey)(value: key.ValueType): Unit = TraceContext.currentContext match {
case ctx: MetricsOnlyContext ⇒ ctx.traceLocalStorage.store(key)(value)
case EmptyTraceContext ⇒ // Can't store in the empty context.
}
- def retrieve(key: TraceLocalKey): Option[key.ValueType] = TraceRecorder.currentContext match {
+ def retrieve(key: TraceLocalKey): Option[key.ValueType] = TraceContext.currentContext match {
case ctx: MetricsOnlyContext ⇒ ctx.traceLocalStorage.retrieve(key)
case EmptyTraceContext ⇒ None // Can't retrieve anything from the empty context.
}
diff --git a/kamon-core/src/main/scala/kamon/trace/TraceRecorder.scala b/kamon-core/src/main/scala/kamon/trace/TraceRecorder.scala
deleted file mode 100644
index 703896c3..00000000
--- a/kamon-core/src/main/scala/kamon/trace/TraceRecorder.scala
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-
-package kamon.trace
-
-import kamon.{ MilliTimestamp, RelativeNanoTimestamp, Kamon }
-
-import scala.language.experimental.macros
-import java.util.concurrent.atomic.AtomicLong
-import kamon.macros.InlineTraceContextMacro
-
-import scala.util.Try
-import java.net.InetAddress
-import akka.actor.ActorSystem
-
-object TraceRecorder {
- private val traceContextStorage = new ThreadLocal[TraceContext] {
- override def initialValue(): TraceContext = EmptyTraceContext
- }
-
- private val tokenCounter = new AtomicLong
- private val hostnamePrefix = Try(InetAddress.getLocalHost.getHostName).getOrElse("unknown-localhost")
-
- def newToken: String = hostnamePrefix + "-" + String.valueOf(tokenCounter.incrementAndGet())
-
- private def newTraceContext(name: String, token: Option[String], system: ActorSystem): TraceContext =
- Kamon(Trace)(system).newTraceContext(name, token.getOrElse(newToken), TraceContextOrigin.Local, system)
-
- def joinRemoteTraceContext(traceName: String, traceToken: String, startTimestamp: MilliTimestamp, isOpen: Boolean, system: ActorSystem): TraceContext = {
- val equivalentStartTimestamp = RelativeNanoTimestamp.relativeTo(startTimestamp)
- Kamon(Trace)(system).newTraceContext(traceName, traceToken, isOpen, TraceContextOrigin.Remote, equivalentStartTimestamp, system)
- }
-
- def setContext(context: TraceContext): Unit = traceContextStorage.set(context)
-
- def clearContext: Unit = traceContextStorage.set(EmptyTraceContext)
-
- def currentContext: TraceContext = traceContextStorage.get()
-
- def start(name: String, token: Option[String] = None)(implicit system: ActorSystem) = {
- val ctx = newTraceContext(name, token, system)
- traceContextStorage.set(ctx)
- }
-
- def rename(name: String): Unit = currentContext.rename(name)
-
- def withNewTraceContext[T](name: String, token: Option[String] = None)(thunk: ⇒ T)(implicit system: ActorSystem): T =
- withTraceContext(newTraceContext(name, token, system))(thunk)
-
- def withTraceContext[T](context: TraceContext)(thunk: ⇒ T): T = {
- val oldContext = currentContext
- setContext(context)
-
- try thunk finally setContext(oldContext)
- }
-
- def withTraceContextAndSystem[T](thunk: (TraceContext, ActorSystem) ⇒ T): Option[T] = currentContext match {
- case ctx: MetricsOnlyContext ⇒ Some(thunk(ctx, ctx.system))
- case EmptyTraceContext ⇒ None
- }
-
- def withInlineTraceContextReplacement[T](traceCtx: TraceContext)(thunk: ⇒ T): T = macro InlineTraceContextMacro.withInlineTraceContextImpl[T, TraceContext]
-
- def finish(): Unit = currentContext.finish()
-
-}
diff --git a/kamon-core/src/main/scala/kamon/trace/TracerExtension.scala b/kamon-core/src/main/scala/kamon/trace/TracerExtension.scala
new file mode 100644
index 00000000..41dcd6bc
--- /dev/null
+++ b/kamon-core/src/main/scala/kamon/trace/TracerExtension.scala
@@ -0,0 +1,94 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013 the kamon project <http://kamon.io/>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ * =========================================================================================
+ */
+
+package kamon.trace
+
+import java.net.InetAddress
+import java.util.concurrent.atomic.AtomicLong
+
+import akka.actor._
+import akka.actor
+import kamon.Kamon
+import kamon.metric.{ Metrics, MetricsExtension }
+import kamon.util.{ NanoInterval, RelativeNanoTimestamp, NanoTimestamp, GlobPathFilter }
+
+import scala.util.Try
+
+object Tracer extends ExtensionId[TracerExtension] with ExtensionIdProvider {
+ override def get(system: ActorSystem): TracerExtension = super.get(system)
+ def lookup(): ExtensionId[_ <: actor.Extension] = Tracer
+ def createExtension(system: ExtendedActorSystem): TracerExtension = new TracerExtensionImpl(system)
+}
+
+trait TracerExtension extends Kamon.Extension {
+ def newContext(name: String): TraceContext
+ def newContext(name: String, token: String): TraceContext
+ def newContext(name: String, token: String, timestamp: RelativeNanoTimestamp, isOpen: Boolean, isLocal: Boolean): TraceContext
+
+ def subscribe(subscriber: ActorRef): Unit
+ def unsubscribe(subscriber: ActorRef): Unit
+}
+
+class TracerExtensionImpl(system: ExtendedActorSystem) extends TracerExtension {
+ private val _settings = TraceSettings(system)
+ private val _metricsExtension = Metrics.get(system)
+
+ private val _hostnamePrefix = Try(InetAddress.getLocalHost.getHostName).getOrElse("unknown-localhost")
+ private val _tokenCounter = new AtomicLong
+ private val _subscriptions = system.actorOf(Props[TraceSubscriptions], "trace-subscriptions")
+ private val _incubator = system.actorOf(Incubator.props(_subscriptions))
+
+ private def newToken: String =
+ _hostnamePrefix + "-" + String.valueOf(_tokenCounter.incrementAndGet())
+
+ def newContext(name: String): TraceContext =
+ createTraceContext(name)
+
+ def newContext(name: String, token: String): TraceContext =
+ createTraceContext(name, token)
+
+ def newContext(name: String, token: String, timestamp: RelativeNanoTimestamp, isOpen: Boolean, isLocal: Boolean): TraceContext =
+ createTraceContext(name, token, timestamp, isOpen, isLocal)
+
+ private def createTraceContext(traceName: String, token: String = newToken, startTimestamp: RelativeNanoTimestamp = RelativeNanoTimestamp.now,
+ isOpen: Boolean = true, isLocal: Boolean = true): TraceContext = {
+
+ def newMetricsOnlyContext = new MetricsOnlyContext(traceName, token, isOpen, _settings.levelOfDetail, startTimestamp, null, _metricsExtension, system)
+
+ if (_settings.levelOfDetail == LevelOfDetail.MetricsOnly || !isLocal)
+ newMetricsOnlyContext
+ else {
+ if (!_settings.sampler.shouldTrace)
+ newMetricsOnlyContext
+ else
+ new TracingContext(traceName, token, true, _settings.levelOfDetail, isLocal, startTimestamp, null, _metricsExtension, this, system, dispatchTracingContext)
+ }
+ }
+
+ def subscribe(subscriber: ActorRef): Unit = _subscriptions ! TraceSubscriptions.Subscribe(subscriber)
+ def unsubscribe(subscriber: ActorRef): Unit = _subscriptions ! TraceSubscriptions.Unsubscribe(subscriber)
+
+ private[kamon] def dispatchTracingContext(trace: TracingContext): Unit =
+ if (_settings.sampler.shouldReport(trace.elapsedTime))
+ if (trace.shouldIncubate)
+ _incubator ! trace
+ else
+ _subscriptions ! trace.generateTraceInfo
+
+}
+
+case class TraceInfo(name: String, token: String, timestamp: NanoTimestamp, elapsedTime: NanoInterval, metadata: Map[String, String], segments: List[SegmentInfo])
+case class SegmentInfo(name: String, category: String, library: String, timestamp: NanoTimestamp, elapsedTime: NanoInterval, metadata: Map[String, String]) \ No newline at end of file
diff --git a/kamon-core/src/main/scala/kamon/trace/TracerExtensionSettings.scala b/kamon-core/src/main/scala/kamon/trace/TracerExtensionSettings.scala
new file mode 100644
index 00000000..e6c2d3ef
--- /dev/null
+++ b/kamon-core/src/main/scala/kamon/trace/TracerExtensionSettings.scala
@@ -0,0 +1,30 @@
+package kamon.trace
+
+import java.util.concurrent.TimeUnit
+
+import akka.actor.ActorSystem
+
+case class TraceSettings(levelOfDetail: LevelOfDetail, sampler: Sampler)
+
+object TraceSettings {
+ def apply(system: ActorSystem): TraceSettings = {
+ val tracerConfig = system.settings.config.getConfig("kamon.trace")
+
+ val detailLevel: LevelOfDetail = tracerConfig.getString("level-of-detail") match {
+ case "metrics-only" ⇒ LevelOfDetail.MetricsOnly
+ case "simple-trace" ⇒ LevelOfDetail.SimpleTrace
+ case other ⇒ sys.error(s"Unknown tracer level of detail [$other] present in the configuration file.")
+ }
+
+ val sampler: Sampler =
+ if (detailLevel == LevelOfDetail.MetricsOnly) NoSampling
+ else tracerConfig.getString("sampling") match {
+ case "all" ⇒ SampleAll
+ case "random" ⇒ new RandomSampler(tracerConfig.getInt("random-sampler.chance"))
+ case "ordered" ⇒ new OrderedSampler(tracerConfig.getInt("ordered-sampler.interval"))
+ case "threshold" ⇒ new ThresholdSampler(tracerConfig.getDuration("threshold-sampler.minimum-elapsed-time", TimeUnit.NANOSECONDS))
+ }
+
+ TraceSettings(detailLevel, sampler)
+ }
+} \ No newline at end of file
diff --git a/kamon-core/src/main/scala/kamon/trace/TracingContext.scala b/kamon-core/src/main/scala/kamon/trace/TracingContext.scala
index 31ab282d..dd4c3c1a 100644
--- a/kamon-core/src/main/scala/kamon/trace/TracingContext.scala
+++ b/kamon-core/src/main/scala/kamon/trace/TracingContext.scala
@@ -21,14 +21,15 @@ import java.util.concurrent.atomic.AtomicInteger
import akka.actor.ActorSystem
import akka.event.LoggingAdapter
-import kamon.{ NanoInterval, NanoTimestamp, RelativeNanoTimestamp }
+import kamon.util.{ NanoInterval, RelativeNanoTimestamp, NanoTimestamp }
import kamon.metric.MetricsExtension
import scala.collection.concurrent.TrieMap
-private[trace] class TracingContext(traceName: String, token: String, izOpen: Boolean, levelOfDetail: LevelOfDetail, origin: TraceContextOrigin,
- startTimeztamp: RelativeNanoTimestamp, log: LoggingAdapter, metricsExtension: MetricsExtension, traceExtension: TraceExtension, system: ActorSystem)
- extends MetricsOnlyContext(traceName, token, izOpen, levelOfDetail, origin, startTimeztamp, log, metricsExtension, system) {
+private[trace] class TracingContext(traceName: String, token: String, izOpen: Boolean, levelOfDetail: LevelOfDetail,
+ isLocal: Boolean, startTimeztamp: RelativeNanoTimestamp, log: LoggingAdapter, metricsExtension: MetricsExtension,
+ traceExtension: TracerExtensionImpl, system: ActorSystem, traceInfoSink: TracingContext ⇒ Unit)
+ extends MetricsOnlyContext(traceName, token, izOpen, levelOfDetail, startTimeztamp, log, metricsExtension, system) {
private val _openSegments = new AtomicInteger(0)
private val _startTimestamp = NanoTimestamp.now
@@ -46,7 +47,7 @@ private[trace] class TracingContext(traceName: String, token: String, izOpen: Bo
override def finish(): Unit = {
super.finish()
- traceExtension.dispatchTracingContext(this)
+ traceInfoSink(this)
}
override def finishSegment(segmentName: String, category: String, library: String, duration: NanoInterval): Unit = {
@@ -66,7 +67,7 @@ private[trace] class TracingContext(traceName: String, token: String, izOpen: Bo
while (currentSegments.hasNext()) {
val segment = currentSegments.next()
if (segment.isClosed)
- segmentsInfo += segment.createSegmentInfo(_startTimestamp, startRelativeTimestamp)
+ segmentsInfo += segment.createSegmentInfo(_startTimestamp, startTimestamp)
else
log.warning("Segment [{}] will be left out of TraceInfo because it was still open.", segment.name)
}
diff --git a/kamon-core/src/main/scala/kamon/trace/logging/LogbackTraceTokenConverter.scala b/kamon-core/src/main/scala/kamon/trace/logging/LogbackTraceTokenConverter.scala
index f052f009..961c3099 100644
--- a/kamon-core/src/main/scala/kamon/trace/logging/LogbackTraceTokenConverter.scala
+++ b/kamon-core/src/main/scala/kamon/trace/logging/LogbackTraceTokenConverter.scala
@@ -17,11 +17,11 @@ package kamon.trace.logging
import ch.qos.logback.classic.pattern.ClassicConverter
import ch.qos.logback.classic.spi.ILoggingEvent
-import kamon.trace.TraceRecorder
+import kamon.trace.TraceContext
class LogbackTraceTokenConverter extends ClassicConverter {
def convert(event: ILoggingEvent): String = {
- val ctx = TraceRecorder.currentContext
+ val ctx = TraceContext.currentContext
if (ctx.isEmpty)
"undefined"
else
diff --git a/kamon-core/src/main/scala/kamon/trace/logging/MdcKeysSupport.scala b/kamon-core/src/main/scala/kamon/trace/logging/MdcKeysSupport.scala
index 4f4efa4d..4970d97e 100644
--- a/kamon-core/src/main/scala/kamon/trace/logging/MdcKeysSupport.scala
+++ b/kamon-core/src/main/scala/kamon/trace/logging/MdcKeysSupport.scala
@@ -17,14 +17,14 @@
package kamon.trace.logging
import kamon.trace.TraceLocal.AvailableToMdc
-import kamon.trace.{ EmptyTraceContext, MetricsOnlyContext, TraceContext, TraceRecorder }
+import kamon.trace.{ EmptyTraceContext, MetricsOnlyContext, TraceContext }
import org.slf4j.MDC
trait MdcKeysSupport {
def withMdc[A](thunk: ⇒ A): A = {
- val keys = copyToMdc(TraceRecorder.currentContext)
+ val keys = copyToMdc(TraceContext.currentContext)
try thunk finally keys.foreach(key ⇒ MDC.remove(key))
}