From 34010efc7b273e50d805a277646f14aa96aaa8b2 Mon Sep 17 00:00:00 2001 From: Ivan Topolnjak Date: Fri, 14 Jul 2017 14:12:47 +0200 Subject: wip --- kamon-core/src/main/scala/kamon/trace/Sampler.scala | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'kamon-core/src/main/scala/kamon/trace/Sampler.scala') diff --git a/kamon-core/src/main/scala/kamon/trace/Sampler.scala b/kamon-core/src/main/scala/kamon/trace/Sampler.scala index 0347a151..f478bbd1 100644 --- a/kamon-core/src/main/scala/kamon/trace/Sampler.scala +++ b/kamon-core/src/main/scala/kamon/trace/Sampler.scala @@ -15,13 +15,16 @@ package kamon.trace +import java.util.concurrent.ThreadLocalRandom +import kamon.trace.SpanContext.SamplingDecision + trait Sampler { - def decide(spanID: Long): Boolean + def decide(operationName: String, builderTags: Map[String, String]): SamplingDecision } object Sampler { - val always = new Constant(true) - val never = new Constant(false) + val always = new Constant(SamplingDecision.Sample) + val never = new Constant(SamplingDecision.DoNotSample) def random(chance: Double): Sampler = { assert(chance >= 0D && chance <= 1.0D, "Change should be >= 0 and <= 1.0") @@ -33,8 +36,8 @@ object Sampler { } } - class Constant(decision: Boolean) extends Sampler { - override def decide(spanID: Long): Boolean = decision + class Constant(decision: SamplingDecision) extends Sampler { + override def decide(operationName: String, builderTags: Map[String, String]): SamplingDecision = decision override def toString: String = s"Sampler.Constant(decision = $decision)" @@ -44,8 +47,10 @@ object Sampler { val upperBoundary = Long.MaxValue * chance val lowerBoundary = -upperBoundary - override def decide(spanID: Long): Boolean = - spanID >= lowerBoundary && spanID <= upperBoundary + override def decide(operationName: String, builderTags: Map[String, String]): SamplingDecision = { + val random = ThreadLocalRandom.current().nextLong() + if(random >= lowerBoundary && random <= upperBoundary) SamplingDecision.Sample else SamplingDecision.DoNotSample + } override def toString: String = s"Sampler.Random(chance = $chance)" -- cgit v1.2.3 From ba35b9859a342bf9d6ceb12e169333f3b68f8b05 Mon Sep 17 00:00:00 2001 From: Ivan Topolnjak Date: Tue, 18 Jul 2017 09:10:59 +0200 Subject: use "probability" instead of "chance" terms for the random sampler --- kamon-core/src/main/resources/reference.conf | 8 ++++---- kamon-core/src/main/scala/kamon/trace/Sampler.scala | 20 ++++++++++---------- kamon-core/src/main/scala/kamon/trace/Tracer.scala | 8 ++++---- 3 files changed, 18 insertions(+), 18 deletions(-) (limited to 'kamon-core/src/main/scala/kamon/trace/Sampler.scala') diff --git a/kamon-core/src/main/resources/reference.conf b/kamon-core/src/main/resources/reference.conf index 6ad06325..06da8e18 100644 --- a/kamon-core/src/main/resources/reference.conf +++ b/kamon-core/src/main/resources/reference.conf @@ -88,17 +88,17 @@ kamon { # Configures a sample that decides which traces should be reported to the trace backends. The possible values are: # - always: report all traces. # - never: don't report any trace. - # - random: use the random tracer. + # - random: randomly decide using the probability defined in the random-sampler.probability setting. # sampler = "random" # The random sampler uses the "chance" setting and a random number to take a decision, if the random number is # on the upper (chance * 100) percent of the number spectrum the trace will be sampled. E.g. a chance of 0.01 will # hint that 1% of all traces should be reported. - sampler-random { + random-sampler { - # Chance of a span being sampled. Must be a value between 0 and 1. - chance = 0.01 + # Probability of a span being sampled. Must be a value between 0 and 1. + probability = 0.01 } } diff --git a/kamon-core/src/main/scala/kamon/trace/Sampler.scala b/kamon-core/src/main/scala/kamon/trace/Sampler.scala index f478bbd1..e2aefe22 100644 --- a/kamon-core/src/main/scala/kamon/trace/Sampler.scala +++ b/kamon-core/src/main/scala/kamon/trace/Sampler.scala @@ -23,15 +23,15 @@ trait Sampler { } object Sampler { - val always = new Constant(SamplingDecision.Sample) - val never = new Constant(SamplingDecision.DoNotSample) + val Always = new Constant(SamplingDecision.Sample) + val Never = new Constant(SamplingDecision.DoNotSample) - def random(chance: Double): Sampler = { - assert(chance >= 0D && chance <= 1.0D, "Change should be >= 0 and <= 1.0") + def random(probability: Double): Sampler = { + assert(probability >= 0D && probability <= 1.0D, "The probability should be >= 0 and <= 1.0") - chance match { - case 0D => never - case 1.0D => always + probability match { + case 0D => Never + case 1.0D => Always case anyOther => new Random(anyOther) } } @@ -43,8 +43,8 @@ object Sampler { s"Sampler.Constant(decision = $decision)" } - class Random(chance: Double) extends Sampler { - val upperBoundary = Long.MaxValue * chance + class Random(probability: Double) extends Sampler { + val upperBoundary = Long.MaxValue * probability val lowerBoundary = -upperBoundary override def decide(operationName: String, builderTags: Map[String, String]): SamplingDecision = { @@ -53,6 +53,6 @@ object Sampler { } override def toString: String = - s"Sampler.Random(chance = $chance)" + s"Sampler.Random(probability = $probability)" } } diff --git a/kamon-core/src/main/scala/kamon/trace/Tracer.scala b/kamon-core/src/main/scala/kamon/trace/Tracer.scala index ecc690af..85d02c8d 100644 --- a/kamon-core/src/main/scala/kamon/trace/Tracer.scala +++ b/kamon-core/src/main/scala/kamon/trace/Tracer.scala @@ -51,7 +51,7 @@ object Tracer { private[Tracer] val tracerMetrics = new TracerMetrics(metrics) @volatile private[Tracer] var joinRemoteSpansWithSameID: Boolean = false - @volatile private[Tracer] var configuredSampler: Sampler = Sampler.never + @volatile private[Tracer] var configuredSampler: Sampler = Sampler.Never @volatile private[Tracer] var identityProvider: IdentityProvider = IdentityProvider.Default() @volatile private[Tracer] var textMapSpanContextCodec: SpanContextCodec[TextMap] = SpanContextCodec.ExtendedB3(identityProvider) @volatile private[Tracer] var httpHeaderSpanContextCodec: SpanContextCodec[TextMap] = SpanContextCodec.ExtendedB3(identityProvider) @@ -99,9 +99,9 @@ object Tracer { val traceConfig = config.getConfig("kamon.trace") configuredSampler = traceConfig.getString("sampler") match { - case "always" => Sampler.always - case "never" => Sampler.never - case "random" => Sampler.random(traceConfig.getDouble("sampler-random.chance")) + case "always" => Sampler.Always + case "never" => Sampler.Never + case "random" => Sampler.random(traceConfig.getDouble("random-sampler.probability")) case other => sys.error(s"Unexpected sampler name $other.") } } -- cgit v1.2.3 From 9b6878da2fbfb1328e972a885a6fdc077e08aaf9 Mon Sep 17 00:00:00 2001 From: Ivan Topolnjak Date: Tue, 18 Jul 2017 10:01:38 +0200 Subject: introduce types for Span tags --- .../src/main/scala/kamon/trace/ActiveSpan.scala | 6 +++ .../src/main/scala/kamon/trace/Sampler.scala | 6 +-- kamon-core/src/main/scala/kamon/trace/Span.scala | 47 +++++++++++++++++----- kamon-core/src/main/scala/kamon/trace/Tracer.scala | 16 +++++++- 4 files changed, 59 insertions(+), 16 deletions(-) (limited to 'kamon-core/src/main/scala/kamon/trace/Sampler.scala') diff --git a/kamon-core/src/main/scala/kamon/trace/ActiveSpan.scala b/kamon-core/src/main/scala/kamon/trace/ActiveSpan.scala index 3753cd7e..68ef2254 100644 --- a/kamon-core/src/main/scala/kamon/trace/ActiveSpan.scala +++ b/kamon-core/src/main/scala/kamon/trace/ActiveSpan.scala @@ -37,6 +37,12 @@ object ActiveSpan { override def addSpanTag(key: String, value: String): Span = wrappedSpan.addSpanTag(key, value) + override def addSpanTag(key: String, value: Long): Span = + wrappedSpan.addSpanTag(key, value) + + override def addSpanTag(key: String, value: Boolean): Span = + wrappedSpan.addSpanTag(key, value) + override def addMetricTag(key: String, value: String): Span = wrappedSpan.addMetricTag(key, value) diff --git a/kamon-core/src/main/scala/kamon/trace/Sampler.scala b/kamon-core/src/main/scala/kamon/trace/Sampler.scala index e2aefe22..3f366175 100644 --- a/kamon-core/src/main/scala/kamon/trace/Sampler.scala +++ b/kamon-core/src/main/scala/kamon/trace/Sampler.scala @@ -19,7 +19,7 @@ import java.util.concurrent.ThreadLocalRandom import kamon.trace.SpanContext.SamplingDecision trait Sampler { - def decide(operationName: String, builderTags: Map[String, String]): SamplingDecision + def decide(operationName: String, builderTags: Map[String, Span.TagValue]): SamplingDecision } object Sampler { @@ -37,7 +37,7 @@ object Sampler { } class Constant(decision: SamplingDecision) extends Sampler { - override def decide(operationName: String, builderTags: Map[String, String]): SamplingDecision = decision + override def decide(operationName: String, builderTags: Map[String, Span.TagValue]): SamplingDecision = decision override def toString: String = s"Sampler.Constant(decision = $decision)" @@ -47,7 +47,7 @@ object Sampler { val upperBoundary = Long.MaxValue * probability val lowerBoundary = -upperBoundary - override def decide(operationName: String, builderTags: Map[String, String]): SamplingDecision = { + override def decide(operationName: String, builderTags: Map[String, Span.TagValue]): SamplingDecision = { val random = ThreadLocalRandom.current().nextLong() if(random >= lowerBoundary && random <= upperBoundary) SamplingDecision.Sample else SamplingDecision.DoNotSample } diff --git a/kamon-core/src/main/scala/kamon/trace/Span.scala b/kamon-core/src/main/scala/kamon/trace/Span.scala index ffe7bed7..ce09a36e 100644 --- a/kamon-core/src/main/scala/kamon/trace/Span.scala +++ b/kamon-core/src/main/scala/kamon/trace/Span.scala @@ -35,6 +35,10 @@ trait BaseSpan { def addSpanTag(key: String, value: String): Span + def addSpanTag(key: String, value: Long): Span + + def addSpanTag(key: String, value: Boolean): Span + def addMetricTag(key: String, value: String): Span def addBaggage(key: String, value: String): Span @@ -64,8 +68,7 @@ trait Span extends BaseSpan { def annotate(timestampMicroseconds: Long, name: String, fields: Map[String, String]): Span = annotate(Span.Annotation(timestampMicroseconds, name, fields)) - - + } object Span { @@ -76,6 +79,8 @@ object Span { override def annotate(annotation: Annotation): Span = this override def addSpanTag(key: String, value: String): Span = this + override def addSpanTag(key: String, value: Long): Span = this + override def addSpanTag(key: String, value: Boolean): Span = this override def addMetricTag(key: String, value: String): Span = this override def addBaggage(key: String, value: String): Span = this override def getBaggage(key: String): Option[String] = None @@ -96,7 +101,7 @@ object Span { * @param startTimestampMicros * @param reporterRegistry */ - final class Real(spanContext: SpanContext, initialOperationName: String, initialTags: Map[String, String], + final class Real(spanContext: SpanContext, initialOperationName: String, initialTags: Map[String, Span.TagValue], startTimestampMicros: Long, reporterRegistry: ReporterRegistryImpl, tracer: Tracer) extends Span { private var collectMetrics: Boolean = true @@ -104,7 +109,7 @@ object Span { private val sampled: Boolean = spanContext.samplingDecision == SamplingDecision.Sample private var operationName: String = initialOperationName - private var spanTags = initialTags + private var spanTags: Map[String, Span.TagValue] = initialTags private var customMetricTags = Map.empty[String, String] private var annotations = List.empty[Span.Annotation] @@ -116,7 +121,21 @@ object Span { override def addSpanTag(key: String, value: String): Span = synchronized { if(sampled && open) - spanTags = spanTags + (key -> value) + spanTags = spanTags + (key -> TagValue.String(value)) + this + } + + override def addSpanTag(key: String, value: Long): Span = synchronized { + if(sampled && open) + spanTags = spanTags + (key -> TagValue.Number(value)) + this + } + + override def addSpanTag(key: String, value: Boolean): Span = synchronized { + if(sampled && open) { + val tagValue = if (value) TagValue.True else TagValue.False + spanTags = spanTags + (key -> tagValue) + } this } @@ -174,7 +193,7 @@ object Span { latencyHistogram.record(elapsedTime) spanTags.get("error").foreach { errorTag => - if(errorTag != null && errorTag.equals(Span.BooleanTagTrueValue)) { + if(errorTag != null && errorTag.equals(TagValue.True)) { Span.Metrics.SpanErrorCount.refine(metricTags).increment() } } @@ -182,20 +201,26 @@ object Span { } object Real { - def apply(spanContext: SpanContext, initialOperationName: String, initialTags: Map[String, String], + def apply(spanContext: SpanContext, initialOperationName: String, initialTags: Map[String, Span.TagValue], startTimestampMicros: Long, reporterRegistry: ReporterRegistryImpl, tracer: Tracer): Real = new Real(spanContext, initialOperationName, initialTags, startTimestampMicros, reporterRegistry, tracer) } + sealed trait TagValue + object TagValue { + sealed trait Boolean extends TagValue + case object True extends Boolean + case object False extends Boolean + + case class String(string: java.lang.String) extends TagValue + case class Number(number: Long) extends TagValue + } object Metrics { val SpanProcessingTimeMetric = Kamon.histogram("span.processing-time", MeasurementUnit.time.microseconds) val SpanErrorCount = Kamon.counter("span.error-count") } - val BooleanTagTrueValue = "1" - val BooleanTagFalseValue = "0" - case class Annotation(timestampMicros: Long, name: String, fields: Map[String, String]) case class FinishedSpan( @@ -203,7 +228,7 @@ object Span { operationName: String, startTimestampMicros: Long, endTimestampMicros: Long, - tags: Map[String, String], + tags: Map[String, Span.TagValue], annotations: Seq[Annotation] ) } \ No newline at end of file diff --git a/kamon-core/src/main/scala/kamon/trace/Tracer.scala b/kamon-core/src/main/scala/kamon/trace/Tracer.scala index c10974f5..d7ca5609 100644 --- a/kamon-core/src/main/scala/kamon/trace/Tracer.scala +++ b/kamon-core/src/main/scala/kamon/trace/Tracer.scala @@ -21,6 +21,7 @@ import java.nio.ByteBuffer import com.typesafe.config.Config import kamon.ReporterRegistryImpl import kamon.metric.MetricLookup +import kamon.trace.Span.TagValue import kamon.trace.SpanContext.{SamplingDecision, Source} import kamon.trace.Tracer.SpanBuilder import kamon.util.Clock @@ -114,7 +115,7 @@ object Tracer { final class SpanBuilder(operationName: String, tracer: Tracer.Default, reporterRegistry: ReporterRegistryImpl) { private var parentContext: SpanContext = _ private var startTimestamp = 0L - private var initialTags = Map.empty[String, String] + private var initialTags = Map.empty[String, Span.TagValue] private var useActiveSpanAsParent = true def asChildOf(parentContext: SpanContext): SpanBuilder = { @@ -126,7 +127,18 @@ object Tracer { asChildOf(parentSpan.context()) def withSpanTag(key: String, value: String): SpanBuilder = { - this.initialTags = this.initialTags + (key -> value) + this.initialTags = this.initialTags + (key -> TagValue.String(value)) + this + } + + def withSpanTag(key: String, value: Long): SpanBuilder = { + this.initialTags = this.initialTags + (key -> TagValue.Number(value)) + this + } + + def withSpanTag(key: String, value: Boolean): SpanBuilder = { + val tagValue = if (value) TagValue.True else TagValue.False + this.initialTags = this.initialTags + (key -> tagValue) this } -- cgit v1.2.3