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
|
package kamon.context
class Context private (private val keys: Map[Key[_], Any]) {
def get[T](key: Key[T]): T =
keys.get(key).getOrElse(key.emptyValue).asInstanceOf[T]
def withKey[T](key: Key[T], value: T): Context =
new Context(keys.updated(key, value))
}
object Context {
val Empty = new Context(Map.empty)
def apply(): Context = Empty
def create(): Context = Empty
}
trait Key[T] {
def name: String
def emptyValue: T
def broadcast: Boolean
}
object Key {
def local[T](name: String, emptyValue: T): Key[T] =
new Default[T](name, emptyValue, false)
def broadcast[T](name: String, emptyValue: T): Key[T] =
new Default[T](name, emptyValue, true)
private class Default[T](val name: String, val emptyValue: T, val broadcast: Boolean) extends Key[T] {
override def hashCode(): Int =
name.hashCode
override def equals(that: Any): Boolean =
that.isInstanceOf[Default[_]] && that.asInstanceOf[Default[_]].name == this.name
}
}
trait Storage {
def current(): Context
def store(context: Context): Scope
trait Scope {
def context: Context
def close(): Unit
}
}
object Storage {
class ThreadLocal extends Storage {
private val tls = new java.lang.ThreadLocal[Context]() {
override def initialValue(): Context = Context.Empty
}
override def current(): Context =
tls.get()
override def store(context: Context): Scope = {
val newContext = context
val previousContext = tls.get()
tls.set(newContext)
new Scope {
override def context: Context = newContext
override def close(): Unit = tls.set(previousContext)
}
}
}
}
trait KeyCodec[T] {
def encode(context: Context): T
def decode(carrier: T, context: Context): Context
}
/*
object Example {
// this is defined somewhere statically, only once.
val User = Key.local[Option[User]]("user", None)
val Client = Key.local[Option[User]]("client", null)
val Span = Key.broadcast[Span]("span", EmptySpan)
val storage = Kamon.contextStorage // or something similar.
storage.get(Span) // returns a Span instance or EmptySpan.
storage.get(User) // Returns Option[User] or None if not set.
storage.get(Client) // Returns Option[Client] or null if not set.
// Context Propagation works the very same way as before.
val scope = storage.store(context)
// do something here
scope.close()
// Configuration for codecs would be handled sort of like this:
// kamon.context.propagation {
// http-header-codecs {
// "span" = kamon.trace.propagation.B3
// }
//
// binary-codecs {
// "span" = kamon.trace.propagation.Binary
// }
// }
}*/
/*
class Context(private val keys: Map[Key[_], Any]) {
}
object Context {
}
sealed trait Key[T] {
def name: String
}
object Key {
def local[T](name: String): Key[T] = Local(name)
case class Local[T](name: String) extends Key[T]
}*/
|