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-1829 Provide 128 bits support for the trace ids in the Tracing sdk #2089

Merged
merged 4 commits into from
Jun 28, 2024

Conversation

mariusc83
Copy link
Member

@mariusc83 mariusc83 commented Jun 19, 2024

What does this PR do?

In this PR we are adding the 128 bits support for our OpenTelemetry and OpenTracing manual APIs + the distributed traces handled through our DatadogInterceptor. The PR contains 3 parts:

  1. 128 bits support for OpenTracing manual API + tests + integration tests updated
  2. 128 bits support for OpenTelemetry manual API + tests + integration tests updated
  3. 128 bits support for the distributed traces in the DatadogInterceptor

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 self-assigned this Jun 19, 2024
@@ -50,6 +51,9 @@
public class DDTracer implements io.opentracing.Tracer, Closeable, Tracer {
// UINT64 max value
Copy link
Member

Choose a reason for hiding this comment

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

seems like comment should be updated?

int samplingPriority = PrioritySampling.UNSET;
String origin = null;
String mostSignificantTraceId = "0";
String lessSignificantTraceId = "0";
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
String lessSignificantTraceId = "0";
String leastSignificantTraceId = "0";

|| parsedValue.compareTo(DDTracer.TRACE_ID_MAX) > 0) {
|| parsedValue.compareTo(DDTracer.SPAN_ID_MAX) > 0) {
Copy link
Member

Choose a reason for hiding this comment

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

why this change is needed?

Copy link
Member Author

Choose a reason for hiding this comment

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

check the method name...this validates a 64bits number and we introduced another one below for 128 bits. We also introduced a SPAN_ID_MAX and TRACE_ID_MAX (one for 64 and the other for 128). Maybe I should re - name these TRACE_ID_64 and TRACE_ID_128 ?

Copy link
Member

Choose a reason for hiding this comment

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

naming should be changed indeed, because using trace word for the lower boundary and span word for the upper boundary is kind of confusing.

private const val HEX_RADIX = 16
private val LONG_MASK = BigInteger("ffffffffffffffff", HEX_RADIX)

fun lessSignificantUnsignedLongAsHexa(traceId: BigInteger): 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
fun lessSignificantUnsignedLongAsHexa(traceId: BigInteger): String {
fun leastSignificantUnsignedLongAsHex(traceId: BigInteger): String {

Comment on lines 18 to 29
@Suppress("MagicNumber")
return traceId.and(LONG_MASK).toString(HEX_RADIX)
}

fun lessSignificantUnsignedLongAsDecimal(traceId: BigInteger): String {
@Suppress("MagicNumber")
return traceId.and(LONG_MASK).toString()
}

fun mostSignificantUnsignedLongAsHexa(traceId: BigInteger): String {
@Suppress("MagicNumber")
return traceId.shiftRight(LONG_BITS_SIZE).toString(HEX_RADIX)
Copy link
Member

Choose a reason for hiding this comment

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

is Suppress(MagicNumber) still needed here? all the arguments are named

@@ -35,16 +36,27 @@ internal class SpanEventAssert(actual: SpanEvent) :
return this
}

fun hasTraceId(traceId: String): SpanEventAssert {
fun hasLessSignificantTraceId(traceId: String): SpanEventAssert {
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
fun hasLessSignificantTraceId(traceId: String): SpanEventAssert {
fun hasLeastSignificantTraceId(traceId: String): SpanEventAssert {

assertThat(actual.traceId)
.overridingErrorMessage(
"Expected SpanEvent to have traceId: $traceId" +
"Expected SpanEvent to have less significant traceId: $traceId" +
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
"Expected SpanEvent to have less significant traceId: $traceId" +
"Expected SpanEvent to have least significant traceId: $traceId" +

" but instead was: ${actual.traceId}"
)
.isEqualTo(traceId)
return this
}

fun hasMostSignificantTraceId(traceId: String): SpanEventAssert {
val lessSignificantTraceId = actual.meta.additionalProperties[TRACE_ID_META_KEY]
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 lessSignificantTraceId = actual.meta.additionalProperties[TRACE_ID_META_KEY]
val mostSignificantTraceId = actual.meta.additionalProperties[TRACE_ID_META_KEY]

Comment on lines 88 to 89
TracingHeaderType.B3,
TracingHeaderType.B3MULTI
Copy link
Member

Choose a reason for hiding this comment

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

do we have this set up on the backend side? is it useful?

Copy link
Member Author

Choose a reason for hiding this comment

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

nope this was just for tests will be removed in the actual PR

Comment on lines 95 to 97
firstPartyHostsWithHeaderType = tracedHosts.associateWith {
tracingHeaderTypes
}
Copy link
Member

Choose a reason for hiding this comment

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

alternatively we can set them up in the core configuration

@mariusc83 mariusc83 force-pushed the mconstantin/rum-1829/use-128-bit-trace-ids branch 6 times, most recently from 8a2f82e to 28c1051 Compare June 24, 2024 11:26
@codecov-commenter
Copy link

codecov-commenter commented Jun 24, 2024

Codecov Report

Attention: Patch coverage is 72.36842% with 42 lines in your changes missing coverage. Please review.

Project coverage is 70.18%. Comparing base (fa1a5f0) to head (446a7b4).
Report is 2 commits behind head on develop.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #2089      +/-   ##
===========================================
+ Coverage    69.68%   70.18%   +0.49%     
===========================================
  Files          718      721       +3     
  Lines        26662    26759      +97     
  Branches      4468     4485      +17     
===========================================
+ Hits         18579    18779     +200     
+ Misses        6857     6733     -124     
- Partials      1226     1247      +21     
Files Coverage Δ
.../android/trace/opentelemetry/OtelTracerProvider.kt 96.50% <100.00%> (ø)
.../kotlin/com/datadog/android/trace/AndroidTracer.kt 96.00% <100.00%> (ø)
...al/domain/event/CoreTracerSpanToSpanEventMapper.kt 88.66% <100.00%> (-0.81%) ⬇️
...e/internal/domain/event/DdSpanToSpanEventMapper.kt 91.80% <100.00%> (+4.30%) ⬆️
...n/com/datadog/android/okhttp/DatadogInterceptor.kt 73.47% <100.00%> (ø)
...datadog/android/okhttp/trace/TracingInterceptor.kt 81.99% <100.00%> (+0.07%) ⬆️
...rc/main/java/com/datadog/opentracing/DDTracer.java 58.82% <91.67%> (+1.18%) ⬆️
...m/datadog/opentracing/propagation/B3HttpCodec.java 5.77% <0.00%> (ø)
.../datadog/opentracing/propagation/B3MHttpCodec.java 0.00% <0.00%> (-6.00%) ⬇️
...dog/opentracing/propagation/HaystackHttpCodec.java 0.00% <0.00%> (ø)
... and 7 more

... and 30 files with indirect coverage changes

@mariusc83 mariusc83 force-pushed the mconstantin/rum-1829/use-128-bit-trace-ids branch from 28c1051 to c385c73 Compare June 24, 2024 12:18
@mariusc83 mariusc83 marked this pull request as ready for review June 24, 2024 12:18
@mariusc83 mariusc83 requested review from a team as code owners June 24, 2024 12:18
@mariusc83 mariusc83 requested a review from 0xnm June 24, 2024 12:41
Copy link
Member

@jonathanmos jonathanmos left a comment

Choose a reason for hiding this comment

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

Nice work! I left a few comments/questions

// BigInteger overflow cannot happen in this context

@Suppress("SwallowedException")
fun leastSignificant64BitsAsHex(traceId: BigInteger): String {
Copy link
Member

Choose a reason for hiding this comment

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

minor: we could add 'safe' to these method names to indicate they won't throw when called

Copy link
Member Author

Choose a reason for hiding this comment

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

good call but I am afraid I am going to run of out space for that method name. Can you give me an example of how this method should be named in that case ?

@@ -2,13 +2,11 @@ Dependencies List

com.squareup.okhttp3:okhttp:4.11.0 : 768 Kb
Copy link
Member

Choose a reason for hiding this comment

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

I've seen this particular change in a few prs unintentionally so just making sure -> in this pr we want this change?

Copy link
Member Author

Choose a reason for hiding this comment

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

As I replied to Nikita above not sure why, need to check what's going on.


@Test
fun `M return empty string W traceIdAsHexString() { ddSpanContext id is null}`() {
// When
Copy link
Member

Choose a reason for hiding this comment

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

Should be Given I think - same for some others in this class

* Returns the span's traceId in hex format.
* The [SpanContext.toTraceId] method returns a string in decimal format,
* which doesn't match what we send in our events
* Returns the span's less significant trace id in hex format (the last 64 bits from the 128 bits trace id)
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
* Returns the span's less significant trace id in hex format (the last 64 bits from the 128 bits trace id)
* Returns the span's least significant trace id in hex format (the last 64 bits from the 128 bits trace id)

@@ -251,7 +251,7 @@ internal class OtelTracerBuilderProviderTest {
val traceId = span.spanContext.traceId

// Then
assertThat(traceId.substring(0, 16)).isEqualTo("0000000000000000")
assertThat(traceId.length).isEqualTo(32)
Copy link
Member

Choose a reason for hiding this comment

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

minor proposal for a better message:

Suggested change
assertThat(traceId.length).isEqualTo(32)
assertThat(traceId).hasSize(32)

Comment on lines -25 to +38
private static final String OT_BAGGAGE_PREFIX = "ot-baggage-";
private static final String TRACE_ID_KEY = "x-datadog-trace-id";
private static final String SPAN_ID_KEY = "x-datadog-parent-id";
private static final String SAMPLING_PRIORITY_KEY = "x-datadog-sampling-priority";
private static final String ORIGIN_KEY = "x-datadog-origin";

private DatadogHttpCodec() {
// This class should not be created. This also makes code coverage checks happy.
}

public static class Injector implements HttpCodec.Injector {

@Override
public void inject(final DDSpanContext context, final TextMapInject carrier) {
carrier.put(TRACE_ID_KEY, context.getTraceId().toString());
carrier.put(SPAN_ID_KEY, context.getSpanId().toString());
final String origin = context.getOrigin();
if (origin != null) {
carrier.put(ORIGIN_KEY, origin);
}

for (final Map.Entry<String, String> entry : context.baggageItems()) {
carrier.put(OT_BAGGAGE_PREFIX + entry.getKey(), HttpCodec.encode(entry.getValue()));
}

// always use max sampling priority for Android traces
carrier.put(SAMPLING_PRIORITY_KEY, "1");
public static final String OT_BAGGAGE_PREFIX = "ot-baggage-";
public static final String LEAST_SIGNIFICANT_TRACE_ID_KEY = "x-datadog-trace-id";
public static final String MOST_SIGNIFICANT_TRACE_ID_KEY = "_dd.p.tid";
public static final String DATADOG_TAGS_KEY = "x-datadog-tags";
public static final String SPAN_ID_KEY = "x-datadog-parent-id";
public static final String SAMPLING_PRIORITY_KEY = "x-datadog-sampling-priority";
public static final String ORIGIN_KEY = "x-datadog-origin";
Copy link
Member

@0xnm 0xnm Jun 24, 2024

Choose a reason for hiding this comment

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

is private -> public change necessary?

Upd: ok, probably for the test?

Comment on lines +59 to +60
final String leastSignificantTraceId = bigIntegerUtils.leastSignificant64BitsAsDecimal(traceId);
final String mostSignificantTraceId = bigIntegerUtils.mostSignificant64BitsAsHex(traceId);
Copy link
Member

Choose a reason for hiding this comment

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

why to we take lower part as decimal, but upper part as hex. some compatibility thing?

Copy link
Member Author

Choose a reason for hiding this comment

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

as stated in the RFC

tags.put(taggedHeaders.get(key), HttpCodec.decode(value));
}
}
if(leastSignificant64BitsTraceIdAsDecimal==null|| mostSignificant64BitsTraceIdAsHex==null){
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
if(leastSignificant64BitsTraceIdAsDecimal==null|| mostSignificant64BitsTraceIdAsHex==null){
if (leastSignificant64BitsTraceIdAsDecimal == null || mostSignificant64BitsTraceIdAsHex == null) {

final String[] tagArray = tags.split(",");
for (String tag : tagArray) {
final String[] tagKeyValue = tag.split("=");
if (tagKeyValue.length >= 2 && tagKeyValue[0].equals(MOST_SIGNIFICANT_TRACE_ID_KEY)) {
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
if (tagKeyValue.length >= 2 && tagKeyValue[0].equals(MOST_SIGNIFICANT_TRACE_ID_KEY)) {
if (tagKeyValue.length >= 2 && MOST_SIGNIFICANT_TRACE_ID_KEY.equals(tagKeyValue[0]) {

Copy link
Member

Choose a reason for hiding this comment

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

should be reverted? why this change comes?

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 I need to see why is this happening as I did not change anything there

}

@Test
fun `M return null W extract { out of bounds less significant trace id }`(forge: Forge) {
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
fun `M return null W extract { out of bounds less significant trace id }`(forge: Forge) {
fun `M return null W extract { out of bounds least significant trace id }`(forge: Forge) {

Comment on lines 212 to 215
val fakeOutOfBoundsLessSignficantTraceId =
BigInteger(forge.aStringMatching("[0-9][a-f]{$outOfBoundsSize}"), 16).toString()
val headers = resolveExtractedHeadersFromSpanContext(fakeDDSpanContext, forge).apply {
set(DatadogHttpCodec.LEAST_SIGNIFICANT_TRACE_ID_KEY, fakeOutOfBoundsLessSignficantTraceId)
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 fakeOutOfBoundsLessSignficantTraceId =
BigInteger(forge.aStringMatching("[0-9][a-f]{$outOfBoundsSize}"), 16).toString()
val headers = resolveExtractedHeadersFromSpanContext(fakeDDSpanContext, forge).apply {
set(DatadogHttpCodec.LEAST_SIGNIFICANT_TRACE_ID_KEY, fakeOutOfBoundsLessSignficantTraceId)
val fakeOutOfBoundsLeastSignficantTraceId =
BigInteger(forge.aStringMatching("[0-9][a-f]{$outOfBoundsSize}"), 16).toString()
val headers = resolveExtractedHeadersFromSpanContext(fakeDDSpanContext, forge).apply {
set(DatadogHttpCodec.LEAST_SIGNIFICANT_TRACE_ID_KEY, fakeOutOfBoundsLeastSignficantTraceId)

@MethodSource("spanContextValues")
fun spanContextValues(): List<DDSpanContext> {
val max128BitsHexa = forge.aStringMatching("[f]{32}")
val minLessSignificant128BitsHexa = forge.aStringMatching("[0]{31}[1]{1}")
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 minLessSignificant128BitsHexa = forge.aStringMatching("[0]{31}[1]{1}")
val minLeastSignificant128BitsHexa = forge.aStringMatching("[0]{31}[1]{1}")

@@ -290,22 +302,24 @@ internal class OtelTracerProviderTest {
val testedProvider = OtelTracerProvider.Builder(stubSdkCore).build()
val tracer = testedProvider.tracerBuilder(fakeInstrumentationName).build()
val blockingWriterWrapper = tracer.useBlockingWriter()
var parentSpanTraceId: String
var lessSignificantParentSpanTraceId: 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
var lessSignificantParentSpanTraceId: String
var leastSignificantParentSpanTraceId: String

Copy link
Member

Choose a reason for hiding this comment

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

still a valid suggestion

@mariusc83 mariusc83 force-pushed the mconstantin/rum-1829/use-128-bit-trace-ids branch from c385c73 to 2a5b4e4 Compare June 25, 2024 07:50
@mariusc83 mariusc83 requested review from jonathanmos and 0xnm June 25, 2024 07:57
@mariusc83 mariusc83 force-pushed the mconstantin/rum-1829/use-128-bit-trace-ids branch 2 times, most recently from 6cc1e75 to 60ee7be Compare June 25, 2024 08:00

private lateinit var fakeTaggedHeaders: Map<String, String>

private lateinit var fakeIdAsHexaString: 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
private lateinit var fakeIdAsHexaString: String
private lateinit var fakeIdAsHexString: String

}

@Test
fun `M return the expected hexa padded string W traceIdAsHexString()`() {
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
fun `M return the expected hexa padded string W traceIdAsHexString()`() {
fun `M return the expected hex padded string W traceIdAsHexString()`() {

@@ -251,7 +251,7 @@ internal class OtelTracerBuilderProviderTest {
val traceId = span.spanContext.traceId

// Then
assertThat(traceId.substring(0, 16)).isEqualTo("0000000000000000")

Choose a reason for hiding this comment

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

/improvement

we should assert on the content of the traceId as well, not just the size.

Copy link
Member Author

Choose a reason for hiding this comment

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

what do you mean the content ? how would you assess that ? Do you mean regex assessment ? That will be too much IMO

Choose a reason for hiding this comment

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

that's the only way we can make sure final version is correct with a plain string assert.

// UINT64 max value
public static final BigInteger TRACE_ID_MAX =
// UINT128 max value
public static final BigInteger TRACE_ID_128_BITS_MAX =

Choose a reason for hiding this comment

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

/question

why do we need to subtract 1? Theoretically an id can be all bits set to 1. ie BigInteger's max value.

Copy link
Member Author

Choose a reason for hiding this comment

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

2^128-1 (we remove the 0). That was already in the java code I am just following the pattern.

@@ -592,6 +596,19 @@ private BigInteger generateNewId() {
return value;
}

private BigInteger generateNewTraceId() {

Choose a reason for hiding this comment

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

/blocking

This shouldn't be any random id but must be in chronologically sorted pattern.

Check https://github.com/DataDog/dd-sdk-ios/blob/380bdf4938519b676d5a1d06bd2ce6928637a0a6/DatadogInternal/Sources/NetworkInstrumentation/TraceID.swift#L222

TLDR

<32-bit unix seconds> <32 bits of zero> <64 random bits>

Copy link
Member Author

Choose a reason for hiding this comment

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

that's the old java code and we need to be consistent with the way the id is generated for spans. I am not touching that part here.

Copy link
Member Author

Choose a reason for hiding this comment

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

why does it need to be chronologically sorted ? Is there a blocking reason behind it ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok I see why, we will switch to the new CoreTracer way of generating ids.

assertThat(lastValue.header(TracingInterceptor.DATADOG_SPAN_ID_HEADER)).isNull()
assertThat(lastValue.header(TracingInterceptor.DATADOG_ORIGIN_HEADER)).isNull()
assertThat(lastValue.header(TracingInterceptor.DATADOG_TAGS)).isNull()

Choose a reason for hiding this comment

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

/improvement

could you also assert on the tag value? this should be higher order part.

Copy link
Member Author

Choose a reason for hiding this comment

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

not sure if it is possible or is not going to be too much. Need to check.

@@ -228,7 +233,7 @@ class UtilitiesTest {
assertThat(eventsWritten).hasSize(1)
val event0 = JsonParser.parseString(eventsWritten[0].eventData) as JsonObject
assertThat(event0.getString("env")).isEqualTo(stubSdkCore.getDatadogContext().env)
assertThat(event0.getString("spans[0].trace_id")).isEqualTo(traceId.toHexString())
assertThat(event0.getString("spans[0].trace_id")).isEqualTo(leastSignificantTraceId)

Choose a reason for hiding this comment

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

/improvement

could you also assert on meta._dd.p.tid?

Copy link
Member Author

Choose a reason for hiding this comment

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

you mean meta._dd.p.id I think ? this property always confuses me as it is _dd.p.id into the distributed traces headers.

@mariusc83 mariusc83 force-pushed the mconstantin/rum-1829/use-128-bit-trace-ids branch 2 times, most recently from 4a9da7e to 975a0e7 Compare June 25, 2024 14:35
@mariusc83 mariusc83 requested a review from ganeshnj June 25, 2024 14:36
@mariusc83 mariusc83 force-pushed the mconstantin/rum-1829/use-128-bit-trace-ids branch from 975a0e7 to f15c224 Compare June 26, 2024 07:05
Copy link

@ganeshnj ganeshnj left a comment

Choose a reason for hiding this comment

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

Overall looks good, could you do some manual testing

  • Distributed traces with all context headers are 128 bits
  • Spans are now shown with 128 bit ids in datadog web app
  • Logs correlations are now using 128 bit
  • RUM events now show 128 bit ids

assertThat(traceId).isNotNull
assertThat(traceId).isNotEqualTo("foo")
assertThat(traceId).isNotEqualTo(DDTraceId.ZERO)
assertThat(traceId).isEqualTo(traceId)

Choose a reason for hiding this comment

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

/blocking

this is always going to be true.

Choose a reason for hiding this comment

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

Assuming Sequential here is what we default do. Could you make sure we assert on the right things here

Something like https://github.com/DataDog/dd-sdk-ios/blob/725e59b118935100c36fe90792c3cb2a26438fe2/DatadogInternal/Tests/NetworkInstrumentation/TraceIDGeneratorTests.swift#L22-L36

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 I ported this test from the APM code, that's weird indeed let me check what they have in original groovy test. I might have missed something

Copy link
Member Author

Choose a reason for hiding this comment

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

I checked, all good that's the test, I think the reason why is to test the reflexivity of equals method: "an object must equal itself"

@mariusc83
Copy link
Member Author

Overall looks good, could you do some manual testing

  • Distributed traces with all context headers are 128 bits
  • Spans are not shown with 128 bit ids in datadog web app
  • Logs correlations are now using 128 bit
  • RUM events now show 128 bit ids

I basically performed all these tests + many other but will double check it now.

@mariusc83 mariusc83 force-pushed the mconstantin/rum-1829/use-128-bit-trace-ids branch from f15c224 to ce9e1f3 Compare June 27, 2024 11:46
@mariusc83 mariusc83 force-pushed the mconstantin/rum-1829/use-128-bit-trace-ids branch 2 times, most recently from 256c37e to 8b3c6ab Compare June 27, 2024 12:41
@mariusc83 mariusc83 requested a review from ganeshnj June 27, 2024 17:52
Copy link
Member

@0xnm 0xnm left a comment

Choose a reason for hiding this comment

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

lgtm, I reviewed it briefly (because I believe that @ganeshnj already reviewed the functional part). There are still some opened comments/suggestions.

}

@Test
fun `M extract unsigned less and most significant bits W extract LSB and MSB`() {
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
fun `M extract unsigned less and most significant bits W extract LSB and MSB`() {
fun `M extract unsigned least and most significant bits W extract LSB and MSB`() {

companion object {
private const val MAX_UNSIGNED_LONG_HEXA_STRING = "ffffffffffffffff"
private const val MIN_UNSIGNED_LONG_HEXA_STRING = "0000000000000000"
private val MAX_EXEC_TIME_IN_NANOS = TimeUnit.MILLISECONDS.toNanos(8)
Copy link
Member

Choose a reason for hiding this comment

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

it is not really relevant, because these are the unit tests, which are executed on JVM, on a server CPU, etc. The execution number you get here is be quite different from the one on the real device.

@@ -68,8 +68,12 @@ internal abstract class TracesTest {
assertThat(expectedSpans.size).isEqualTo(sentSpansObjects.size)
expectedSpans.forEach { span ->
val json = sentSpansObjects.first {
it.get(TRACE_ID_KEY).asString == Long.toHexString((span.traceId.toLong())) &&
it.get(SPAN_ID_KEY).asString == Long.toHexString((span.spanId.toLong()))
val leasSignificantTraceId = it.get(TRACE_ID_KEY).asString
Copy link
Member

Choose a reason for hiding this comment

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

this suggestion is still valid

val leasSignificantTraceId = it.get(TRACE_ID_KEY).asString
val mostSignificantTraceId = it.getAsJsonObject("meta")
.getAsJsonPrimitive(MOST_SIGNIFICANT_64_BITS_TRACE_ID_KEY).asString
leasSignificantTraceId == span.leastSignificant64BitsTraceId() &&
Copy link
Member

Choose a reason for hiding this comment

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

this suggestion is still valid

fun Span.traceIdAsHexString(): String {
return context().toTraceId().toLong().toHexString()
fun Span.leastSignificant64BitsTraceId(): String {
return (this as? DDSpan)?.traceId?.toString(16)?.padStart(32, '0')?.takeLast(16) ?: ""
Copy link
Member

Choose a reason for hiding this comment

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

will we be aware about the cases when we get empty string? nothing will crash?

Copy link
Member Author

Choose a reason for hiding this comment

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

based on the code we have there is no way we could get empty strings here as the generator is tested above and other tests will fail first. Here the debate is either we add these logs just for the sake of it or we just don't and consider this safe.

Copy link
Member Author

Choose a reason for hiding this comment

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

also we will be aware as I added this extra checks:

  hasValidMostSignificant64BitsTraceId()
  hasValidLeastSignificant64BitsTraceId()

They validate the regEx

@@ -290,22 +302,24 @@ internal class OtelTracerProviderTest {
val testedProvider = OtelTracerProvider.Builder(stubSdkCore).build()
val tracer = testedProvider.tracerBuilder(fakeInstrumentationName).build()
val blockingWriterWrapper = tracer.useBlockingWriter()
var parentSpanTraceId: String
var lessSignificantParentSpanTraceId: String
Copy link
Member

Choose a reason for hiding this comment

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

still a valid suggestion

@mariusc83 mariusc83 force-pushed the mconstantin/rum-1829/use-128-bit-trace-ids branch from 8b3c6ab to 446a7b4 Compare June 28, 2024 09:44
@mariusc83 mariusc83 merged commit 6772159 into develop Jun 28, 2024
19 checks passed
@mariusc83 mariusc83 deleted the mconstantin/rum-1829/use-128-bit-trace-ids branch June 28, 2024 12:33
@xgouchet xgouchet added this to the 2.12.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.

6 participants