diff options
Diffstat (limited to 'kamon-core/src/legacy-main/scala/kamon/trace/TraceContext.scala')
-rw-r--r-- | kamon-core/src/legacy-main/scala/kamon/trace/TraceContext.scala | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/kamon-core/src/legacy-main/scala/kamon/trace/TraceContext.scala b/kamon-core/src/legacy-main/scala/kamon/trace/TraceContext.scala new file mode 100644 index 00000000..bbf40d8d --- /dev/null +++ b/kamon-core/src/legacy-main/scala/kamon/trace/TraceContext.scala @@ -0,0 +1,202 @@ +/* + * ========================================================================================= + * Copyright © 2013-2016 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.io.ObjectStreamException +import java.util + +import kamon.trace.Status.Closed +import kamon.trace.TraceContextAware.DefaultTraceContextAware +import kamon.util.{Function, RelativeNanoTimestamp, SameThreadExecutionContext, Supplier} + +import scala.concurrent.Future + +trait TraceContext { + def name: String + def token: String + def tags: Map[String, String] + def isEmpty: Boolean + def nonEmpty: Boolean = !isEmpty + def isClosed: Boolean = !(Status.Open == status) + def status: Status + def finish(): Unit + def finishWithError(cause: Throwable): Unit + def rename(newName: String): Unit + def startSegment(segmentName: String, category: String, library: String): Segment + def startSegment(segmentName: String, category: String, library: String, tags: Map[String, String]): Segment + def addMetadata(key: String, value: String): Unit + def addTag(key: String, value: String): Unit + def removeTag(key: String, value: String): Boolean + def startTimestamp: RelativeNanoTimestamp + + def collect[T](f: TraceContext ⇒ T): Option[T] = + if (nonEmpty) + Some(f(this)) + else None + + def collect[T](f: Function[TraceContext, T]): Option[T] = + if (nonEmpty) + Some(f(this)) + else None + + def withNewSegment[T](segmentName: String, category: String, library: String)(code: ⇒ T): T = { + withNewSegment(segmentName, category, library, Map.empty[String, String])(code) + } + + def withNewSegment[T](segmentName: String, category: String, library: String, tags: Map[String, String])(code: ⇒ T): T = { + val segment = startSegment(segmentName, category, library, tags) + try code finally segment.finish() + } + + def withNewAsyncSegment[T](segmentName: String, category: String, library: String)(code: ⇒ Future[T]): Future[T] = { + withNewAsyncSegment(segmentName, category, library, Map.empty[String, String])(code) + } + + def withNewAsyncSegment[T](segmentName: String, category: String, library: String, tags: Map[String, String])(code: ⇒ Future[T]): Future[T] = { + val segment = startSegment(segmentName, category, library, tags) + val result = code + result.onComplete(_ ⇒ segment.finish())(SameThreadExecutionContext) + result + } + + // Java variant. + def withNewSegment[T](segmentName: String, category: String, library: String, code: Supplier[T]): T = + withNewSegment(segmentName, category, library)(code.get) + + def withNewSegment[T](segmentName: String, category: String, library: String, tags: util.Map[String, String], code: Supplier[T]): T = { + import scala.collection.JavaConverters._ + withNewSegment(segmentName, category, library, tags.asScala.toMap)(code.get) + } +} + +trait Segment { + def name: String + def category: String + def library: String + def tags: Map[String, String] + def isEmpty: Boolean + def nonEmpty: Boolean = !isEmpty + def isClosed: Boolean = !(Status.Open == status) + def status: Status + def finish(): Unit + def finishWithError(cause: Throwable): Unit + def rename(newName: String): Unit + def addMetadata(key: String, value: String): Unit + def addTag(key: String, value: String): Unit + def removeTag(key: String, value: String): Boolean +} + +case object EmptyTraceContext extends TraceContext { + def name: String = "empty-trace" + def token: String = "" + def tags: Map[String, String] = Map.empty + def isEmpty: Boolean = true + def status: Status = Closed + def finish(): Unit = {} + def finishWithError(cause: Throwable): Unit = {} + def rename(name: String): Unit = {} + def startSegment(segmentName: String, category: String, library: String): Segment = EmptySegment + def startSegment(segmentName: String, category: String, library: String, tags: Map[String, String]): Segment = EmptySegment + def addMetadata(key: String, value: String): Unit = {} + def startTimestamp = new RelativeNanoTimestamp(0L) + def addTag(key: String, value: String): Unit = {} + def removeTag(key: String, value: String): Boolean = false + + case object EmptySegment extends Segment { + val name: String = "empty-segment" + val category: String = "empty-category" + val library: String = "empty-library" + def tags: Map[String, String] = Map.empty + def isEmpty: Boolean = true + def status: Status = Closed + def finish(): Unit = {} + def finishWithError(cause: Throwable): Unit = {} + def rename(newName: String): Unit = {} + def addMetadata(key: String, value: String): Unit = {} + def addTag(key: String, value: String): Unit = {} + def removeTag(key: String, value: String): Boolean = false + } +} + +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 + case object SimpleTrace extends LevelOfDetail + case object FullTrace extends LevelOfDetail +} + +sealed trait Status +object Status { + case object Open extends Status + case object Closed extends Status + case object FinishedWithError extends Status + case object FinishedSuccessfully extends Status +} + +trait TraceContextAware extends Serializable { + def traceContext: TraceContext +} + +object TraceContextAware { + def default: TraceContextAware = new DefaultTraceContextAware + + class DefaultTraceContextAware extends TraceContextAware { + @transient val traceContext = Tracer.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 @transient var segment: Segment = EmptyTraceContext.EmptySegment +} + +object SegmentAware { + def default: SegmentAware = new DefaultSegmentAware + class DefaultSegmentAware extends DefaultTraceContextAware with SegmentAware {} +}
\ No newline at end of file |