aboutsummaryrefslogtreecommitdiff
path: root/kamon-core/src/main/scala/kamon/trace/ActiveSpanStorage.scala
blob: 85e94ef2018cf4bdce4f86b5212135576461fa64 (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
package kamon.trace

/**
  * A means of storing and retrieving the currently active Span. The application code execution is always considered to
  * contribute to the completion of the operation represented by the currently active Span.
  *
  * The activation of a Span is of temporary nature and users of this API must ensure that all Scopes created via calls
  * to `activate(span)` are timely closed; failing to do so might lead to unexpected behavior. Typically, the same block
  * of code designating a Span as currently active will close the created Scope after finishing execution.
  *
  */
trait ActiveSpanStorage {

  /**
    * @return the currently active Span.
    */
  def activeSpan(): Span

  /**
    * Sets
    * @param span the Span to be set as currently active.
    * @return a [[Scope]] that will finish the designation of the given Span as active once it's closed.
    */
  def activate(span: Span): Scope

}

/**
  * Encapsulates the state (if any) required to handle the removal of a Span from it's currently active designation.
  *
  * Typically a Scope will enclose the previously active Span and return the previously active Span when closed,
  * although no assumptions are made.
  *
  */
trait Scope extends AutoCloseable {

  /**
    * Removes the currently active Span from the ActiveSpanStorage.
    *
    */
  def close(): Unit
}

object ActiveSpanStorage {

  /**
    * A ActiveSpanStorage that uses a [[java.lang.ThreadLocal]] as the underlying storage.
    *
    */
  final class ThreadLocal extends ActiveSpanStorage {
    private val emptySpan = Span.Empty(this)
    private val storage: java.lang.ThreadLocal[Span] = new java.lang.ThreadLocal[Span] {
      override def initialValue(): Span = emptySpan
    }

    override def activeSpan(): Span =
      storage.get()

    override def activate(span: Span): Scope = {
      val previouslyActiveSpan = storage.get()
      storage.set(span)

      new Scope {
        override def close(): Unit = {
          storage.set(previouslyActiveSpan)
        }
      }
    }
  }

  object ThreadLocal {
    def apply(): ThreadLocal = new ThreadLocal()
  }
}