Introduce a common abstractions to handle tags #572
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Background and Motivation
We are heavy users of the "tags" term around Kamon, we currently have metric tags, span tags and since #552 we also have context tags (merged but not released yet). Still, tags were not treated equally all around. In the metrics and context sections they were a
Map[String, String]
but on the tracer tags could beBoolean
,Long
orString
values. Furthermore, accessing the tags might be annoying, specially if accessing them from non-Scala language (Java, I'm looking at your) so the idea came to mind: what if we could have a single abstraction for handling a group of key/value pairs and use it throughout the entire code base? so the work on this PR started.Goals
This is how we hope this PR will improve Kamon's user experience:
Solution on this PR
We are introducing two main concepts on this PR:
TagSet
which is an immutable set of key/value pairs meant to replace the previousMap[String, String]
and similar implementations.TagSet
instances can be constructed from existing maps or by explicitly providing each key/value pair to be included in it.TagSet.Lookup
interface and several built-in implementations of it. ALookup
'a task is to take a raw, untyped map that is used as the actual storage for the tags and return certain representation of the value. It can be that some users want to get a String ornull
if not present, or anOptional[String]
, or just force whatever is there on the map to become a string (specially useful when logging things from the Context). Lookups provide a simple and typed way of accessing the contents of aTagSet
, without prescribing or limiting the ways in which missing or unexpected values are treated.Here is an example of how using these tags look like:
Lookup names are biased towards
String
values since they tend to be by far the most common case, that's what you can get aplain
String but you need to useplainLong
orplainBoolean
if you are searching for a values with long or boolean types, respectively.Finally, notice the
coerce
Lookup which will always return a String value, regardless of the actual type of the tag, which should come in very handy when trying to log tags from a Context.Scope
As part of this PR I'm only changing the implementation of Tags for context Tags and including all the required changes for this to work when doing Context propagation over HTTP and Binary transports and separate PRs will be issued for introducing these changes to the Metrics and Tracing APIs as well.