RUM-4116 Add the SpanLink support for Otel API implementation#1993
Conversation
799a676 to
89ec036
Compare
89ec036 to
fec3fba
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## feature/otel-support #1993 +/- ##
========================================================
+ Coverage 60.26% 60.29% +0.04%
========================================================
Files 808 808
Lines 30184 30196 +12
Branches 4945 4950 +5
========================================================
+ Hits 18188 18206 +18
- Misses 10772 10775 +3
+ Partials 1224 1215 -9
🚀 New features to boost your workflow:
|
| private fun Forge.exhaustiveAttributes(): Map<String, String> { | ||
| return listOf( | ||
| aString() | ||
| ).map { anAlphabeticalString() to it } | ||
| .toMap(mutableMapOf()) | ||
| } |
There was a problem hiding this comment.
no need to redefine it, you should be able to import one defined in tools:unit module (com.datadog.tools.unit.forge package). Anyway, in this particular case it is not exhaustive attributes, because it is always String to String
There was a problem hiding this comment.
yes that is the reason why I did not import it but you are right I need to change that name
| whenever(it.baggageItems).thenReturn(baggageItems) | ||
| whenever(it.tags).thenReturn(tagsAndMetrics) | ||
| } | ||
| val spanLinks = forge.aList(size = forge.anInt(min = 0, max = 10)) { forge.getForgery<AgentSpanLink>() } |
There was a problem hiding this comment.
| val spanLinks = forge.aList(size = forge.anInt(min = 0, max = 10)) { forge.getForgery<AgentSpanLink>() } | |
| val spanLinks = forge.aList(size = forge.anInt(min = 0, max = 10)) { getForgery<AgentSpanLink>() } |
|
|
||
| companion object { | ||
| internal const val RUM_ENDPOINT_REQUIRED_TRACE_ID_LENGTH = 16 | ||
| private const val LESS_SIGNIFICANT_64_BITS_AS_HEXA_LENGTH = 16 |
There was a problem hiding this comment.
We probably need to use word hex instead of hexa. The only usages of hexa I find is for color (which makes sense because it is RGB as hex + alpha as hex). Same applies for other mentions of hexa in this PR.
Also it should be least, not less for LSB (least significant bits).
| private const val LESS_SIGNIFICANT_64_BITS_AS_HEXA_LENGTH = 16 | |
| private const val LEAST_SIGNIFICANT_64_BITS_AS_HEX_LENGTH = 16 |
| return model.traceId.toHexString().takeLast(RUM_ENDPOINT_REQUIRED_TRACE_ID_LENGTH) | ||
| // because the backend endpoint does not support 32 hexa characters trace ids we are going to take only the | ||
| // less significant 64 bits of the trace id. Later on when we will introduce the 128 bits support | ||
| // the more significant bits will be reported in a separated dedicated meta tag. |
There was a problem hiding this comment.
| // the more significant bits will be reported in a separated dedicated meta tag. | |
| // the most significant bits will be reported in a separated dedicated meta tag. |
| ) | ||
| val tags = event.tags.mapValues { it.value.toString() } | ||
| val meta = (event.baggage + tags).toMutableMap() | ||
| val meta: MutableMap<String, String> = mutableMapOf() |
There was a problem hiding this comment.
minor suggestion
| val meta: MutableMap<String, String> = mutableMapOf() | |
| val meta = mutableMapOf<String, String>() |
| } | ||
|
|
||
| private fun resolveSpanLink(link: AgentSpanLink): JsonObject { | ||
| // The SpanLinks support the full 128 bits trace so we can use the full hexa string |
There was a problem hiding this comment.
| // The SpanLinks support the full 128 bits trace so we can use the full hexa string | |
| // The SpanLinks support the full 128 bits trace so we can use the full hex string |
| val actualLink = deserializedLinks[index].asJsonObject | ||
| val actualTraceId = actualLink.get("trace_id").asString | ||
| val traceId = link.traceId().toHexString() | ||
| assertThat(actualTraceId) | ||
| .overridingErrorMessage( | ||
| "Expected SpanEvent to have span link trace id: " + | ||
| "$traceId but " + | ||
| "instead was: $actualTraceId" | ||
| ) | ||
| .isEqualTo(traceId) | ||
| val actualSpanId = actualLink.get("span_id").asString | ||
| val spanId = DDSpanId.toHexStringPadded(link.spanId()) | ||
| assertThat(actualSpanId) | ||
| .overridingErrorMessage( | ||
| "Expected SpanEvent to have span link span id: " + | ||
| "$spanId but " + | ||
| "instead was: $$actualSpanId" | ||
| ) | ||
| .isEqualTo(spanId) | ||
| val traceFlags = link.traceFlags() | ||
| if (traceFlags.toInt() != 0) { | ||
| val actualTraceFlags = actualLink.get("flags").asByte | ||
| assertThat(actualTraceFlags) | ||
| .overridingErrorMessage( | ||
| "Expected SpanEvent to have span link flags: " + | ||
| "$traceFlags but " + | ||
| "instead was: $actualTraceFlags" | ||
| ) | ||
| .isEqualTo(traceFlags) | ||
| } else { | ||
| assertThat(actualLink.has("flags")) | ||
| .overridingErrorMessage( | ||
| "Expected SpanEvent to not have span link flags but " + | ||
| "instead was: $actualLink" | ||
| ) | ||
| .isFalse() | ||
| } | ||
| val actualTraceState = actualLink.get("tracestate").asString | ||
| if (actualTraceState.isNotEmpty()) { | ||
| val traceState = link.traceState() | ||
| assertThat(actualTraceState) | ||
| .overridingErrorMessage( | ||
| "Expected SpanEvent to have span link trace state: " + | ||
| "$traceState but " + | ||
| "instead was: $actualTraceState" | ||
| ) | ||
| .isEqualTo(traceState) | ||
| } else { | ||
| assertThat(actualLink.has("tracestate")) | ||
| .overridingErrorMessage( | ||
| "Expected SpanEvent to not have span link trace state but " + | ||
| "instead was: $actualLink" | ||
| ) | ||
| .isFalse() | ||
| } | ||
| val actualAttributes = actualLink.get("attributes").toString() | ||
| val expectedAttributes = link.attributes().asMap() | ||
| val jsonObject = JsonObject() | ||
| expectedAttributes.forEach { (key, value) -> | ||
| jsonObject.addProperty(key, value) | ||
| } | ||
| val expectedAttributesJsonString = jsonObject.toString() | ||
| assertThat(actualAttributes) | ||
| .overridingErrorMessage( | ||
| "Expected SpanEvent to have span link attributes: " + | ||
| "$expectedAttributesJsonString but " + | ||
| "instead was: $actualAttributes" | ||
| ) | ||
| .isEqualTo(expectedAttributesJsonString) |
There was a problem hiding this comment.
not blocking: maybe extract this into a dedicated assert / split assertions? a bit hard to read
fec3fba to
94ba118
Compare
cd0841b to
40ec44a
Compare
| - "kotlin.String.substringAfter(kotlin.Char, kotlin.String)" | ||
| - "kotlin.String.substringAfterLast(kotlin.Char, kotlin.String)" | ||
| - "kotlin.String.substringBefore(kotlin.Char, kotlin.String)" | ||
| - "kotlin.String.takeLessSignificant64Bits()" |
There was a problem hiding this comment.
| - "kotlin.String.takeLessSignificant64Bits()" | |
| - "kotlin.String.takeLeastSignificant64Bits()" |
40ec44a to
f28a8cf
Compare
What does this PR do?
The Otel
SpanBuilder#addLinkAPI delegates to theDDSpanunder the hood and adds anAgentSpanLinkto it.In this PR we are adding the links support into our
OtelDdSpanToSpanEventMapperby serializing theAgentSpanLinklist and adding it as aString/Stringentry into theSpanEvent.metamap.Example of a serialized span link into the
metasection:Motivation
What inspired you to submit this pull request?
Additional Notes
Anything else we should know when reviewing?
Review checklist (to be filled by reviewers)