From cd54e4ed73734dbabebbf22e4fa288c9b047992e Mon Sep 17 00:00:00 2001 From: Ivan Topolnjak Date: Thu, 24 Aug 2017 11:23:21 +0200 Subject: introduce the SpanCustomizer API --- kamon-core/src/main/scala/kamon/Kamon.scala | 5 +++- .../main/scala/kamon/trace/SpanCustomizer.scala | 35 ++++++++++++++++++++++ kamon-core/src/main/scala/kamon/trace/Tracer.scala | 16 ++++++++-- 3 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 kamon-core/src/main/scala/kamon/trace/SpanCustomizer.scala (limited to 'kamon-core/src') diff --git a/kamon-core/src/main/scala/kamon/Kamon.scala b/kamon-core/src/main/scala/kamon/Kamon.scala index f251b1ec..e83f6a5c 100644 --- a/kamon-core/src/main/scala/kamon/Kamon.scala +++ b/kamon-core/src/main/scala/kamon/Kamon.scala @@ -24,7 +24,7 @@ import scala.concurrent.Future import java.time.Duration import java.util.concurrent.{Executors, ScheduledExecutorService, ScheduledThreadPoolExecutor} -import kamon.context.{Codecs, Context, Storage} +import kamon.context.{Codecs, Context, Key, Storage} import org.slf4j.LoggerFactory import scala.util.Try @@ -118,6 +118,9 @@ object Kamon extends MetricLookup with ReporterRegistry with Tracer { } } + def withContextKey[T, K](key: Key[K], value: K)(f: => T): T = + withContext(currentContext().withKey(key, value))(f) + override def loadReportersFromConfig(): Unit = _reporterRegistry.loadReportersFromConfig() diff --git a/kamon-core/src/main/scala/kamon/trace/SpanCustomizer.scala b/kamon-core/src/main/scala/kamon/trace/SpanCustomizer.scala new file mode 100644 index 00000000..4c6220ce --- /dev/null +++ b/kamon-core/src/main/scala/kamon/trace/SpanCustomizer.scala @@ -0,0 +1,35 @@ +package kamon.trace + +import kamon.context.Key +import kamon.trace.Tracer.SpanBuilder + +/** + * Allows users to customize and add additional information to Spans created by instrumentation. The typical use + * case for SpanCustomizer instances is to provide proper operation names in situations where the instrumentation + * is unable to generate a reasonable enough operation name, e.g. JDBC and HTTP Client calls, instead of having a + * default operation name using the statement type or target host a SpanCustomizer can be provided to assign operation + * names like "queryUsers" or "getUserProfile" instead. + * + * Instrumentation wanting to take advantage of SpanCustomizers should look for an instance in the current context + * using SpanCustomizer.ContextKey. + * + */ +trait SpanCustomizer { + def customize(spanBuilder: SpanBuilder): SpanBuilder +} + +object SpanCustomizer { + + val Noop = new SpanCustomizer { + override def customize(spanBuilder: SpanBuilder): SpanBuilder = spanBuilder + } + + val ContextKey = Key.local[SpanCustomizer]("span-customizer", Noop) + + def forOperationName(operationName: String): SpanCustomizer = new SpanCustomizer { + override def customize(spanBuilder: SpanBuilder): SpanBuilder = + spanBuilder.withOperationName(operationName) + } +} + + diff --git a/kamon-core/src/main/scala/kamon/trace/Tracer.scala b/kamon-core/src/main/scala/kamon/trace/Tracer.scala index 5f61f3aa..8fa5df5d 100644 --- a/kamon-core/src/main/scala/kamon/trace/Tracer.scala +++ b/kamon-core/src/main/scala/kamon/trace/Tracer.scala @@ -91,6 +91,7 @@ object Tracer { final class SpanBuilder(operationName: String, tracer: Tracer.Default, spanSink: SpanSink) { private var parentSpan: Span = _ + private var initialOperationName: String = operationName private var startTimestamp = 0L private var initialSpanTags = Map.empty[String, Span.TagValue] private var initialMetricTags = Map.empty[String, String] @@ -133,6 +134,17 @@ object Tracer { this } + def withOperationName(operationName: String): SpanBuilder = { + this.initialOperationName = operationName + this + } + + def spanTags: Map[String, Span.TagValue] = + this.initialSpanTags + + def metricTags: Map[String, String] = + this.initialMetricTags + def ignoreParentFromContext(): SpanBuilder = { this.useParentFromContext = false this @@ -150,7 +162,7 @@ object Tracer { val samplingDecision: SamplingDecision = parentSpan .map(_.context.samplingDecision) .filter(_ != SamplingDecision.Unknown) - .getOrElse(tracer.sampler.decide(operationName, initialSpanTags)) + .getOrElse(tracer.sampler.decide(initialOperationName, initialSpanTags)) val spanContext = parentSpan match { case Some(parent) => joinParentContext(parent, samplingDecision) @@ -158,7 +170,7 @@ object Tracer { } tracer.tracerMetrics.createdSpans.increment() - Span.Local(spanContext, nonRemoteParent, operationName, initialSpanTags, initialMetricTags, startTimestampMicros, spanSink, tracer.scopeSpanMetrics) + Span.Local(spanContext, nonRemoteParent, initialOperationName, initialSpanTags, initialMetricTags, startTimestampMicros, spanSink, tracer.scopeSpanMetrics) } private def joinParentContext(parent: Span, samplingDecision: SamplingDecision): SpanContext = -- cgit v1.2.3