Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public static void InjectTraceIntoData<TRecordRequest>(Tracer tracer, TRecordReq
// payload was parsed to json.
if (payloadSize != 0 && payloadSize > MaxDsmHeaderSize)
{
dataStreamsManager.InjectPathwayContext(scope.Span.Context.PathwayContext, adapter);
dataStreamsManager.InjectPathwayContextAsBase64String(scope.Span.Context.PathwayContext, adapter);
}

propagatedContext = adapter.GetDictionary();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

#nullable enable

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
Expand All @@ -14,7 +13,7 @@

namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.Kinesis
{
internal struct KinesisContextAdapter : IHeadersCollection, IBinaryHeadersCollection
internal struct KinesisContextAdapter : IHeadersCollection
{
private Dictionary<string, List<string>> headers = new Dictionary<string, List<string>>();

Expand Down Expand Up @@ -59,20 +58,5 @@ public void Remove(string name)
{
headers.Remove(name);
}

public byte[] TryGetLastBytes(string name)
{
if (headers.TryGetValue(name, out var value))
{
return Convert.FromBase64String(value[value.Count - 1]);
}

return [];
}

public void Add(string name, byte[] value)
{
Add(name, Convert.ToBase64String(value));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.Shared;

internal static class AwsMessageAttributesHeadersAdapters
{
public static IBinaryHeadersCollection GetInjectionAdapter(StringBuilder carrier)
public static IBinaryHeadersCollection GetInjectionAdapter(StringBuilder carrier, bool legacyEncodingBehaviorEnabled)
{
return new StringBuilderJsonAdapter(carrier);
return new StringBuilderJsonAdapter(carrier, legacyEncodingBehaviorEnabled);
}

public static IBinaryHeadersCollection GetExtractionAdapter(IDictionary? messageAttributes)
Expand All @@ -36,10 +36,12 @@ public static IBinaryHeadersCollection GetExtractionAdapter(IDictionary? message
private readonly struct StringBuilderJsonAdapter : IBinaryHeadersCollection
{
private readonly StringBuilder _carrier;
private readonly bool _legacyEncodingBehaviorEnabled;

public StringBuilderJsonAdapter(StringBuilder carrier)
public StringBuilderJsonAdapter(StringBuilder carrier, bool legacyEncodingBehaviorEnabled)
{
_carrier = carrier;
_legacyEncodingBehaviorEnabled = legacyEncodingBehaviorEnabled;
}

public byte[] TryGetLastBytes(string name)
Expand All @@ -49,16 +51,18 @@ public byte[] TryGetLastBytes(string name)

public void Add(string key, byte[] value)
{
// FIXME BREAKING CHANGE:
// We are preserving the existing bug with the extra Base64 layer on the Base64 pathway header
// We will address this as a follow up
Comment thread
robcarlan-datadog marked this conversation as resolved.
Resolved
_carrier
.Append(value: '"')
.Append(key)
.Append("\":\"")
.Append(Convert.ToBase64String(value))
.Append(ToJsonSafeString(key, value))
.Append("\",");
}

private string ToJsonSafeString(string key, byte[] value)
=> key == DataStreamsPropagationHeaders.PropagationKeyBase64 && !_legacyEncodingBehaviorEnabled
? Encoding.UTF8.GetString(value)
: Convert.ToBase64String(value);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private static void Inject(Tracer tracer, PropagationContext context, IDictionar

if (context.SpanContext?.PathwayContext is { } pathwayContext)
{
dataStreamsManager?.InjectPathwayContext(pathwayContext, AwsMessageAttributesHeadersAdapters.GetInjectionAdapter(sb));
dataStreamsManager?.InjectPathwayContext(pathwayContext, AwsMessageAttributesHeadersAdapters.GetInjectionAdapter(sb, tracer.Settings.IsDataStreamsLegacyEncodingBehaviorEnabled));
}

sb.Remove(startIndex: sb.Length - 1, length: 1); // Remove trailing comma
Expand Down
9 changes: 9 additions & 0 deletions tracer/src/Datadog.Trace/Configuration/TracerSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,10 @@ not null when string.Equals(value, "otlp", StringComparison.OrdinalIgnoreCase) =
.WithKeys(ConfigurationKeys.DataStreamsMonitoring.LegacyHeadersEnabled)
.AsBool(!IsDataStreamsMonitoringInDefaultState);

IsDataStreamsLegacyEncodingBehaviorEnabled = config
.WithKeys(ConfigurationKeys.DataStreamsMonitoring.LegacyEncodingBehaviorEnabled)
.AsBool(false);

IsRareSamplerEnabled = config
.WithKeys(ConfigurationKeys.RareSamplerEnabled)
.AsBool(false);
Expand Down Expand Up @@ -1362,6 +1366,11 @@ bool DisableIfOtelSdkDisabled(bool enabled, string key)
/// </summary>
internal bool IsDataStreamsLegacyHeadersEnabled { get; }

/// <summary>
/// Gets a value indicating whether SQS and SNS producers double Base64 encode the Data Streams pathway context.
/// </summary>
internal bool IsDataStreamsLegacyEncodingBehaviorEnabled { get; }

/// <summary>
/// Gets a value indicating whether the rare sampler is enabled or not.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,17 @@ supportedConfigurations:
documentation: |-
Enables data streams monitoring support
<see cref="Datadog.Trace.Configuration.TracerSettings.IsDataStreamsMonitoringEnabled"/>
DD_DATA_STREAMS_LEGACY_ENCODING_BEHAVIOR_ENABLED:
- implementation: A
scope: managed
type: boolean
default: 'false'
product: DataStreamsMonitoring
const_name: LegacyEncodingBehaviorEnabled
documentation: |-
Configuration key for restoring the legacy double Base64 encoding of the Data Streams pathway context in SQS and SNS messages.
Enable while consumers still run a tracer version older than 3.55.0.
<see cref="Datadog.Trace.Configuration.TracerSettings.IsDataStreamsLegacyEncodingBehaviorEnabled"/>
DD_DATA_STREAMS_LEGACY_HEADERS:
- implementation: A
scope: managed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ internal static class DataStreamsMonitoring
/// </summary>
public const string Enabled = "DD_DATA_STREAMS_ENABLED";

/// <summary>
/// Configuration key for restoring the legacy double Base64 encoding of the Data Streams pathway context in SQS and SNS messages.
/// Enable while consumers still run a tracer version older than 3.55.0.
/// <see cref="Datadog.Trace.Configuration.TracerSettings.IsDataStreamsLegacyEncodingBehaviorEnabled"/>
/// </summary>
public const string LegacyEncodingBehaviorEnabled = "DD_DATA_STREAMS_LEGACY_ENCODING_BEHAVIOR_ENABLED";

/// <summary>
/// Configuration key for enabling legacy binary headers in Data Streams Monitoring.
/// false by default if DSM is in default state, true otherwise
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ internal static class DataStreamsMonitoring
/// </summary>
public const string Enabled = "DD_DATA_STREAMS_ENABLED";

/// <summary>
/// Configuration key for restoring the legacy double Base64 encoding of the Data Streams pathway context in SQS and SNS messages.
/// Enable while consumers still run a tracer version older than 3.55.0.
/// <see cref="Datadog.Trace.Configuration.TracerSettings.IsDataStreamsLegacyEncodingBehaviorEnabled"/>
/// </summary>
public const string LegacyEncodingBehaviorEnabled = "DD_DATA_STREAMS_LEGACY_ENCODING_BEHAVIOR_ENABLED";

/// <summary>
/// Configuration key for enabling legacy binary headers in Data Streams Monitoring.
/// false by default if DSM is in default state, true otherwise
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ internal static class DataStreamsMonitoring
/// </summary>
public const string Enabled = "DD_DATA_STREAMS_ENABLED";

/// <summary>
/// Configuration key for restoring the legacy double Base64 encoding of the Data Streams pathway context in SQS and SNS messages.
/// Enable while consumers still run a tracer version older than 3.55.0.
/// <see cref="Datadog.Trace.Configuration.TracerSettings.IsDataStreamsLegacyEncodingBehaviorEnabled"/>
/// </summary>
public const string LegacyEncodingBehaviorEnabled = "DD_DATA_STREAMS_LEGACY_ENCODING_BEHAVIOR_ENABLED";

/// <summary>
/// Configuration key for enabling legacy binary headers in Data Streams Monitoring.
/// false by default if DSM is in default state, true otherwise
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ internal static class DataStreamsMonitoring
/// </summary>
public const string Enabled = "DD_DATA_STREAMS_ENABLED";

/// <summary>
/// Configuration key for restoring the legacy double Base64 encoding of the Data Streams pathway context in SQS and SNS messages.
/// Enable while consumers still run a tracer version older than 3.55.0.
/// <see cref="Datadog.Trace.Configuration.TracerSettings.IsDataStreamsLegacyEncodingBehaviorEnabled"/>
/// </summary>
public const string LegacyEncodingBehaviorEnabled = "DD_DATA_STREAMS_LEGACY_ENCODING_BEHAVIOR_ENABLED";

/// <summary>
/// Configuration key for enabling legacy binary headers in Data Streams Monitoring.
/// false by default if DSM is in default state, true otherwise
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,19 +236,18 @@ public void Extract_InvalidLegacyHeader_ReturnsNull(bool binaryAttribute)

[Theory]
[CombinatorialData]
public void Inject_PreservesExistingDotnetWireFormat(bool legacyHeadersEnabled)
public void Inject_EncodesPathwayOnceUnlessLegacyEncodingEnabled(bool legacyHeadersEnabled, bool legacyEncodingBehaviorEnabled)
{
var carrier = new StringBuilder("{");
var adapter = AwsMessageAttributesHeadersAdapters.GetInjectionAdapter(carrier);
var adapter = AwsMessageAttributesHeadersAdapters.GetInjectionAdapter(carrier, legacyEncodingBehaviorEnabled);
var context = new PathwayContext(new PathwayHash(Hash), 1_700_000_000_000_000_000, 1_700_000_001_000_000_000);

DataStreamsContextPropagator.Instance.Inject(context, adapter, legacyHeadersEnabled);
carrier.Length--; // Remove the trailing comma written by the injection adapter.
carrier.Append('}');
var headers = JsonConvert.DeserializeObject<Dictionary<string, string>>(carrier.ToString());

// Existing .NET consumers expect two Base64 layers for this header.
headers[DataStreamsPropagationHeaders.PropagationKeyBase64].Should().Be(EncodeAgain(Pathway));
headers[DataStreamsPropagationHeaders.PropagationKeyBase64].Should().Be(legacyEncodingBehaviorEnabled ? EncodeAgain(Pathway) : Pathway);
if (legacyHeadersEnabled)
{
headers[DataStreamsPropagationHeaders.PropagationKey].Should().Be(Pathway);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Datadog.Trace.Agent;
using Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.Kinesis;
using Datadog.Trace.Configuration;
using Datadog.Trace.DataStreamsMonitoring;
using Datadog.Trace.DuckTyping;
using Datadog.Trace.Sampling;
using Datadog.Trace.TestHelpers.TestTracer;
Expand Down Expand Up @@ -202,6 +203,11 @@ public async Task InjectTraceIntoData_WithJsonString_AddsTraceContext()
extractedTraceContext["x-datadog-parent-id"].Should().Be(scope?.Span.SpanId.ToString());
extractedTraceContext["x-datadog-trace-id"].Should().Be(scope?.Span.TraceId.ToString());
extractedTraceContext["dd-pathway-ctx-base64"].As<Newtonsoft.Json.Linq.JArray>().Should().HaveCount(1);

var pathway = extractedTraceContext["dd-pathway-ctx-base64"].As<Newtonsoft.Json.Linq.JArray>()[0].ToString();
var decoded = PathwayContextEncoder.Decode(Convert.FromBase64String(pathway));
decoded.Should().NotBeNull();
decoded!.Value.Hash.Should().Be(scope!.Span.Context.PathwayContext!.Value.Hash);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,16 @@ public void IsDataStreamsLegacyHeadersEnabled(string value, bool expected)
settings.IsDataStreamsLegacyHeadersEnabled.Should().Be(expected);
}

[Theory]
[MemberData(nameof(BooleanTestCases), false)]
public void IsDataStreamsLegacyEncodingBehaviorEnabled(string value, bool expected)
{
var source = CreateConfigurationSource((ConfigurationKeys.DataStreamsMonitoring.LegacyEncodingBehaviorEnabled, value));
var settings = new TracerSettings(source);

settings.IsDataStreamsLegacyEncodingBehaviorEnabled.Should().Be(expected);
}

[Theory]
[InlineData("1", true)]
[InlineData("0", false)]
Expand Down
Loading