Skip to content

Commit

Permalink
allow arbitrary header names for automatic broadcast string keys
Browse files Browse the repository at this point in the history
  • Loading branch information
ivantopo committed Feb 2, 2018
1 parent 16a23e2 commit 91b01c6
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 13 deletions.
5 changes: 5 additions & 0 deletions kamon-core-tests/src/test/resources/reference.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kamon {
context.codecs.string-keys {
request-id = "X-Request-ID"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ class ContextCodecSpec extends WordSpec with Matchers with ContextTesting with O
decodedContext.get(StringKey) shouldBe empty
decodedContext.get(StringBroadcastKey).value shouldBe "this-should-be-round-tripped"
}

"read string broadcast keys using the configured header name" in {
val textMap = TextMap.Default()
textMap.put("X-Request-ID", "123456")
val decodedContext = ContextCodec.HttpHeaders.decode(textMap)

decodedContext.get(Key.broadcastString("request-id")).value shouldBe "123456"
}
}

"encoding/decoding to Binary" should {
Expand Down
19 changes: 18 additions & 1 deletion kamon-core/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,24 @@ kamon {
# Size of the encoding buffer for the Binary Codec.
binary-buffer-size = 256

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

}

# Codecs to be used when propagating a Context through a HTTP Headers transport.
http-headers-keys {
Expand Down
22 changes: 11 additions & 11 deletions kamon-core/src/main/scala/kamon/context/Codecs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class Codecs(initialConfig: Config) {
import scala.collection.JavaConverters._
try {
val codecsConfig = config.getConfig("kamon.context.codecs")
val stringKeys = codecsConfig.getStringList("string-keys").asScala
val stringKeys = readStringKeysConfig(codecsConfig.getConfig("string-keys"))
val knownHttpHeaderCodecs = readEntryCodecs[TextMap]("http-headers-keys", codecsConfig) ++ stringHeaderCodecs(stringKeys)
val knownBinaryCodecs = readEntryCodecs[ByteBuffer]("binary-keys", codecsConfig) ++ stringBinaryCodecs(stringKeys)

Expand Down Expand Up @@ -72,13 +72,14 @@ class Codecs(initialConfig: Config) {
entries.result()
}

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

private def stringBinaryCodecs(keys: Seq[String]): Map[String, Codecs.ForEntry[ByteBuffer]] = {
keys.map(key => (key, new Codecs.StringBinaryCodec(key))).toMap
}
private def stringHeaderCodecs(keys: Map[String, String]): Map[String, Codecs.ForEntry[TextMap]] =
keys.map { case (key, header) => (key, new Codecs.StringHeadersCodec(key, header)) }

private def stringBinaryCodecs(keys: Map[String, String]): Map[String, Codecs.ForEntry[ByteBuffer]] =
keys.map { case (key, _) => (key, new Codecs.StringBinaryCodec(key)) }
}

object Codecs {
Expand Down Expand Up @@ -224,21 +225,20 @@ object Codecs {
}
}

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

override def encode(context: Context): TextMap = {
val textMap = TextMap.Default()
context.get(contextKey).foreach { value =>
textMap.put(dataKey, value)
textMap.put(headerName, value)
}

textMap
}

override def decode(carrier: TextMap, context: Context): Context = {
carrier.get(dataKey) match {
carrier.get(headerName) match {
case value @ Some(_) => context.withKey(contextKey, value)
case None => context
}
Expand Down
4 changes: 3 additions & 1 deletion kamon-testkit/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
kamon {
context.codecs {
string-keys = [ "string-broadcast-key" ]
string-keys {
string-broadcast-key = "X-string-broadcast-key"
}
}
}

0 comments on commit 91b01c6

Please sign in to comment.