Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RUM-4116 Add the SpanLink support for Otel API implementation #1993

Conversation

mariusc83
Copy link
Member

What does this PR do?

The Otel SpanBuilder#addLink API delegates to the DDSpan under the hood and adds an AgentSpanLink to it.
In this PR we are adding the links support into our OtelDdSpanToSpanEventMapper by serializing the AgentSpanLink list and adding it as a String/String entry into the SpanEvent.meta map.
Example of a serialized span link into the meta section:

_dd.span_links -> "[
    {
        "attributes": {
            "key": "value"
        },
        "flags": 1,
        "span_id": "4ab9b106d00b9366",
        "trace_id": "000000000000000015b5cedc8e96fd32"
    }
]"

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)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)

@mariusc83 mariusc83 force-pushed the mconstantin/rum-4116/add-spanlink-support-for-otel-tracer branch from 799a676 to 89ec036 Compare April 17, 2024 11:34
@mariusc83 mariusc83 marked this pull request as ready for review April 17, 2024 11:34
@mariusc83 mariusc83 requested review from a team as code owners April 17, 2024 11:34
@mariusc83 mariusc83 force-pushed the mconstantin/rum-4116/add-spanlink-support-for-otel-tracer branch from 89ec036 to fec3fba Compare April 17, 2024 11:42
@mariusc83 mariusc83 self-assigned this Apr 17, 2024
@codecov-commenter
Copy link

codecov-commenter commented Apr 17, 2024

Codecov Report

Merging #1993 (f28a8cf) into feature/otel-support (37e2e35) will increase coverage by 0.04%.
The diff coverage is 86.11%.

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     
Files Coverage Δ
...dog/android/trace/internal/data/OtelTraceWriter.kt 88.89% <ø> (+3.70%) ⬆️
...e/src/main/java/com/datadog/trace/core/DDSpan.java 55.98% <0.00%> (-0.24%) ⬇️
...ternal/domain/event/OtelDdSpanToSpanEventMapper.kt 88.42% <88.57%> (+2.06%) ⬆️

... and 29 files with indirect coverage changes

xgouchet
xgouchet previously approved these changes Apr 17, 2024
Comment on lines 36 to 40
private fun Forge.exhaustiveAttributes(): Map<String, String> {
return listOf(
aString()
).map { anAlphabeticalString() to it }
.toMap(mutableMapOf())
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes that is the reason why I did not import it but you are right I need to change that name

@@ -35,6 +36,8 @@ internal class CoreDDSpanForgeryFactory : ForgeryFactory<DDSpan> {
whenever(it.baggageItems).thenReturn(baggageItems)
whenever(it.tags).thenReturn(tagsAndMetrics)
}
val spanLinks = forge.aList(size = forge.anInt(min = 0, max = 10)) { forge.getForgery<AgentSpanLink>() }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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>() }

// endregion

companion object {
internal const val RUM_ENDPOINT_REQUIRED_TRACE_ID_LENGTH = 16
private const val LESS_SIGNIFICANT_64_BITS_AS_HEXA_LENGTH = 16
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Suggested change
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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// 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.

@@ -90,7 +104,10 @@ internal class OtelDdSpanToSpanEventMapper(
view = event.tags[LogAttributes.RUM_VIEW_ID]?.let { SpanEvent.View(it as? String) }
)
val tags = event.tags.mapValues { it.value.toString() }
val meta = (event.baggage + tags).toMutableMap()
val meta: MutableMap<String, String> = mutableMapOf()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor suggestion

Suggested change
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// 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

Comment on lines 325 to 423
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not blocking: maybe extract this into a dedicated assert / split assertions? a bit hard to read

@mariusc83 mariusc83 force-pushed the mconstantin/rum-4116/add-spanlink-support-for-otel-tracer branch from fec3fba to 94ba118 Compare April 17, 2024 15:44
@mariusc83 mariusc83 requested review from 0xnm and xgouchet April 17, 2024 15:44
@mariusc83 mariusc83 force-pushed the mconstantin/rum-4116/add-spanlink-support-for-otel-tracer branch 2 times, most recently from cd0841b to 40ec44a Compare April 17, 2024 15:46
jonathanmos
jonathanmos previously approved these changes Apr 18, 2024
0xnm
0xnm previously approved these changes Apr 18, 2024
@@ -1120,6 +1120,7 @@ datadog:
- "kotlin.String.substringAfter(kotlin.Char, kotlin.String)"
- "kotlin.String.substringAfterLast(kotlin.Char, kotlin.String)"
- "kotlin.String.substringBefore(kotlin.Char, kotlin.String)"
- "kotlin.String.takeLessSignificant64Bits()"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- "kotlin.String.takeLessSignificant64Bits()"
- "kotlin.String.takeLeastSignificant64Bits()"

@mariusc83 mariusc83 dismissed stale reviews from 0xnm and jonathanmos via f28a8cf April 18, 2024 12:26
@mariusc83 mariusc83 force-pushed the mconstantin/rum-4116/add-spanlink-support-for-otel-tracer branch from 40ec44a to f28a8cf Compare April 18, 2024 12:26
@mariusc83 mariusc83 merged commit c88c271 into feature/otel-support Apr 18, 2024
25 checks passed
@mariusc83 mariusc83 deleted the mconstantin/rum-4116/add-spanlink-support-for-otel-tracer branch April 18, 2024 13:18
@xgouchet xgouchet added this to the 2.11.x milestone Jul 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants