Skip to content

Commit fa342db

Browse files
authored
Merge pull request #509 from ivantopo/issue#505/arbitrary-header-names-for-string-keys
allow arbitrary header names for automatic broadcast string keys, fixes #505
2 parents 16a23e2 + 91b01c6 commit fa342db

File tree

5 files changed

+45
-13
lines changed

5 files changed

+45
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kamon {
2+
context.codecs.string-keys {
3+
request-id = "X-Request-ID"
4+
}
5+
}

kamon-core-tests/src/test/scala/kamon/context/ContextCodecSpec.scala

+8
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ class ContextCodecSpec extends WordSpec with Matchers with ContextTesting with O
4848
decodedContext.get(StringKey) shouldBe empty
4949
decodedContext.get(StringBroadcastKey).value shouldBe "this-should-be-round-tripped"
5050
}
51+
52+
"read string broadcast keys using the configured header name" in {
53+
val textMap = TextMap.Default()
54+
textMap.put("X-Request-ID", "123456")
55+
val decodedContext = ContextCodec.HttpHeaders.decode(textMap)
56+
57+
decodedContext.get(Key.broadcastString("request-id")).value shouldBe "123456"
58+
}
5159
}
5260

5361
"encoding/decoding to Binary" should {

kamon-core/src/main/resources/reference.conf

+18-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,24 @@ kamon {
150150
# Size of the encoding buffer for the Binary Codec.
151151
binary-buffer-size = 256
152152

153-
string-keys = [ ]
153+
# Declarative definition of broadcast context keys with type Option[String]. The setting key represents the actual
154+
# key name and the value is the HTTP header name to be used to encode/decode the context key. The key name will
155+
# be used when coding for binary transport. The most common use case for string keys is effortless propagation of
156+
# correlation keys or request related data (locale, user ID, etc). E.g. if wanting to propagate a "X-Request-ID"
157+
# header this config should suffice:
158+
#
159+
# kamon.context.codecs.string-keys {
160+
# request-id = "X-Request-ID"
161+
# }
162+
#
163+
# If the application must read this context key they can define key with a matching name and read the value from
164+
# the context:
165+
# val requestIDKey = Key.broadcastString("request-id") // Do this only once, keep a reference.
166+
# val requestID = Kamon.currentContext().get(requestIDKey)
167+
#
168+
string-keys {
169+
170+
}
154171

155172
# Codecs to be used when propagating a Context through a HTTP Headers transport.
156173
http-headers-keys {

kamon-core/src/main/scala/kamon/context/Codecs.scala

+11-11
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class Codecs(initialConfig: Config) {
4343
import scala.collection.JavaConverters._
4444
try {
4545
val codecsConfig = config.getConfig("kamon.context.codecs")
46-
val stringKeys = codecsConfig.getStringList("string-keys").asScala
46+
val stringKeys = readStringKeysConfig(codecsConfig.getConfig("string-keys"))
4747
val knownHttpHeaderCodecs = readEntryCodecs[TextMap]("http-headers-keys", codecsConfig) ++ stringHeaderCodecs(stringKeys)
4848
val knownBinaryCodecs = readEntryCodecs[ByteBuffer]("binary-keys", codecsConfig) ++ stringBinaryCodecs(stringKeys)
4949

@@ -72,13 +72,14 @@ class Codecs(initialConfig: Config) {
7272
entries.result()
7373
}
7474

75-
private def stringHeaderCodecs(keys: Seq[String]): Map[String, Codecs.ForEntry[TextMap]] = {
76-
keys.map(key => (key, new Codecs.StringHeadersCodec(key))).toMap
77-
}
75+
private def readStringKeysConfig(config: Config): Map[String, String] =
76+
config.topLevelKeys.map(key => (key, config.getString(key))).toMap
7877

79-
private def stringBinaryCodecs(keys: Seq[String]): Map[String, Codecs.ForEntry[ByteBuffer]] = {
80-
keys.map(key => (key, new Codecs.StringBinaryCodec(key))).toMap
81-
}
78+
private def stringHeaderCodecs(keys: Map[String, String]): Map[String, Codecs.ForEntry[TextMap]] =
79+
keys.map { case (key, header) => (key, new Codecs.StringHeadersCodec(key, header)) }
80+
81+
private def stringBinaryCodecs(keys: Map[String, String]): Map[String, Codecs.ForEntry[ByteBuffer]] =
82+
keys.map { case (key, _) => (key, new Codecs.StringBinaryCodec(key)) }
8283
}
8384

8485
object Codecs {
@@ -224,21 +225,20 @@ object Codecs {
224225
}
225226
}
226227

227-
private class StringHeadersCodec(key: String) extends Codecs.ForEntry[TextMap] {
228-
private val dataKey = "X-KamonContext-" + key
228+
private class StringHeadersCodec(key: String, headerName: String) extends Codecs.ForEntry[TextMap] {
229229
private val contextKey = Key.broadcast[Option[String]](key, None)
230230

231231
override def encode(context: Context): TextMap = {
232232
val textMap = TextMap.Default()
233233
context.get(contextKey).foreach { value =>
234-
textMap.put(dataKey, value)
234+
textMap.put(headerName, value)
235235
}
236236

237237
textMap
238238
}
239239

240240
override def decode(carrier: TextMap, context: Context): Context = {
241-
carrier.get(dataKey) match {
241+
carrier.get(headerName) match {
242242
case value @ Some(_) => context.withKey(contextKey, value)
243243
case None => context
244244
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
kamon {
22
context.codecs {
3-
string-keys = [ "string-broadcast-key" ]
3+
string-keys {
4+
string-broadcast-key = "X-string-broadcast-key"
5+
}
46
}
57
}

0 commit comments

Comments
 (0)