aboutsummaryrefslogtreecommitdiff
path: root/kamon-core/src/test/scala/kamon/trace/TracerSpec.scala
blob: 5abfe723480dce1011bc7d9275d4af12e59b7e0e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package kamon.trace

import com.typesafe.config.ConfigFactory
import kamon.Kamon
import kamon.testkit.{SpanBuilding, SpanInspector}
import kamon.trace.Span.TagValue
import kamon.trace.SpanContext.Source
import kamon.trace.SpanContextCodec.Format
import org.scalatest.{Matchers, OptionValues, WordSpec}

class TracerSpec extends WordSpec with Matchers with SpanBuilding with OptionValues {

  "the Kamon tracer" should {
    "construct a minimal Span that only has a operation name" in {
      val span = tracer.buildSpan("myOperation").start()
      val spanData = inspect(span)

      spanData.operationName() shouldBe "myOperation"
      spanData.metricTags() shouldBe empty
      spanData.spanTags() shouldBe empty
    }

    "pass the operation name and tags to started Span" in {
      val span = tracer.buildSpan("myOperation")
        .withMetricTag("metric-tag", "value")
        .withMetricTag("metric-tag", "value")
        .withSpanTag("hello", "world")
        .withSpanTag("kamon", "rulez")
        .withSpanTag("number", 123)
        .withSpanTag("boolean", true)
        .start()

      val spanData = inspect(span)
      spanData.operationName() shouldBe "myOperation"
      spanData.metricTags() should contain only (
        ("metric-tag" -> "value"))

      spanData.spanTags() should contain allOf(
        ("hello" -> TagValue.String("world")),
        ("kamon" -> TagValue.String("rulez")),
        ("number" -> TagValue.Number(123)),
        ("boolean" -> TagValue.True))
    }

//    "do not interfere with the currently active Span if not requested when starting a Span" in {
//      val previouslyActiveSpan = tracer.activeSpan()
//      tracer.buildSpan("myOperation").start()
//      tracer.activeSpan() should be theSameInstanceAs(previouslyActiveSpan)
//    }
//
//    "make a span active with started with the .startActive() function and restore the previous Span when deactivated" in {
//      val previouslyActiveSpan = tracer.activeSpan()
//      val activeSpan = tracer.buildSpan("myOperation").startActive()
//
//      tracer.activeSpan() shouldNot be theSameInstanceAs(previouslyActiveSpan)
//      val activeSpanData = inspect(activeSpan)
//      activeSpanData.operationName() shouldBe "myOperation"
//
//      activeSpan.deactivate()
//      tracer.activeSpan() should be theSameInstanceAs(previouslyActiveSpan)
//    }

    "not have any parent Span if there is ActiveSpan and no parent was explicitly given" in {
      val span = tracer.buildSpan("myOperation").start()
      val spanData = inspect(span)
      spanData.context().parentID shouldBe IdentityProvider.NoIdentifier
    }

    "use the currently active span as parent" in {
      val parent = tracer.buildSpan("myOperation").start()
      val child = Kamon.withActiveSpan(parent) {
        tracer.buildSpan("childOperation").asChildOf(parent).start()
      }

      val parentData = inspect(parent)
      val childData = inspect(child)
      parentData.context().spanID shouldBe childData.context().parentID
    }

    "ignore the currently active span as parent if explicitly requested" in {
      val parent = tracer.buildSpan("myOperation").start()
      val child = Kamon.withActiveSpan(parent) {
        tracer.buildSpan("childOperation").ignoreActiveSpan().start()
      }

      val childData = inspect(child)
      childData.context().parentID shouldBe IdentityProvider.NoIdentifier
    }

    "allow overriding the start timestamp for a Span" in {
      val span = tracer.buildSpan("myOperation").withStartTimestamp(100).start()
      val spanData = inspect(span)
      spanData.startTimestamp() shouldBe 100
    }

    "inject and extract a SpanContext from a TextMap carrier" in {
      val spanContext = createSpanContext()
      val injected = Kamon.inject(spanContext, Format.TextMap)
      val extractedSpanContext = Kamon.extract(Format.TextMap, injected).value

      spanContext.traceID shouldBe(extractedSpanContext.traceID)
      spanContext.spanID shouldBe(extractedSpanContext.spanID)
      spanContext.parentID shouldBe(extractedSpanContext.parentID)
      spanContext.baggage.getAll() shouldBe(extractedSpanContext.baggage.getAll())
    }

    "inject and extract a SpanContext from a TextMap carrier supplied by the caller" in {
      val spanContext = createSpanContext()
      val carrier = TextMap.Default()
      Kamon.inject(spanContext, Format.TextMap, carrier)
      val extractedSpanContext = Kamon.extract(Format.TextMap, carrier).value

      spanContext.traceID shouldBe(extractedSpanContext.traceID)
      spanContext.spanID shouldBe(extractedSpanContext.spanID)
      spanContext.parentID shouldBe(extractedSpanContext.parentID)
      spanContext.baggage.getAll() shouldBe(extractedSpanContext.baggage.getAll())
    }

    "inject and extract a SpanContext from a HttpHeaders carrier" in {
      val spanContext = createSpanContext()
      val injected = Kamon.inject(spanContext, Format.HttpHeaders)
      val extractedSpanContext = Kamon.extract(Format.HttpHeaders, injected).value

      spanContext.traceID shouldBe(extractedSpanContext.traceID)
      spanContext.spanID shouldBe(extractedSpanContext.spanID)
      spanContext.parentID shouldBe(extractedSpanContext.parentID)
      spanContext.baggage.getAll() shouldBe(extractedSpanContext.baggage.getAll())
    }

    "inject and extract a SpanContext from a HttpHeaders using a TextMap provided by the caller" in {
      val spanContext = createSpanContext()
      val carrier = TextMap.Default()
      Kamon.inject(spanContext, Format.HttpHeaders, carrier)
      val extractedSpanContext = Kamon.extract(Format.HttpHeaders, carrier).value

      spanContext.traceID shouldBe(extractedSpanContext.traceID)
      spanContext.spanID shouldBe(extractedSpanContext.spanID)
      spanContext.parentID shouldBe(extractedSpanContext.parentID)
      spanContext.baggage.getAll() shouldBe(extractedSpanContext.baggage.getAll())
    }


    "preserve the same Span and Parent identifier when creating a Span with a remote parent if join-remote-parents-with-same-span-id is enabled" in {
      val previousConfig = Kamon.config()

      Kamon.reconfigure {
        ConfigFactory.parseString("kamon.trace.join-remote-parents-with-same-span-id = yes")
          .withFallback(Kamon.config())
      }

      val remoteParent = createSpanContext().copy(source = Source.Remote)
      val childData = inspect(tracer.buildSpan("local").asChildOf(remoteParent).start())

      childData.context().traceID shouldBe remoteParent.traceID
      childData.context().parentID shouldBe remoteParent.parentID
      childData.context().spanID shouldBe remoteParent.spanID

      Kamon.reconfigure(previousConfig)
    }

  }

  val tracer: Tracer = Kamon

  def inspect(span: Span): SpanInspector =
    SpanInspector(span)

}