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

Switch .NET tracer to injecting both base64 & binary headers #6448

Merged
merged 39 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
4431a45
switch .NET tracer to injecting both base64 & binary headers
veerbia Nov 7, 2024
8361b37
fix context propagation issues
veerbia Nov 7, 2024
2abc2c9
Merge branch 'master' into veerbia/base64migration
veerbia Nov 8, 2024
703d9b5
Merge branch 'master' into veerbia/base64migration
veerbia Nov 19, 2024
5373d94
Merge branch 'master' into veerbia/base64migration
veerbia Nov 20, 2024
fd9cdc3
add newline
veerbia Nov 20, 2024
d9f8cc9
fix tryfromb64string
veerbia Nov 20, 2024
f4f6af4
change default to true
veerbia Nov 20, 2024
1c5bbd9
Merge branch 'master' into veerbia/base64migration
veerbia Nov 20, 2024
b721d66
test fixes
veerbia Nov 20, 2024
111682b
rm trail ws
veerbia Nov 20, 2024
721a8fe
rm trail ws
veerbia Nov 20, 2024
523a3cb
move private member to bottom
veerbia Nov 20, 2024
6dfb7ff
fix static before non static
veerbia Nov 20, 2024
598fe6a
fix tests
veerbia Nov 21, 2024
f7d971d
modify test approach
veerbia Nov 21, 2024
bd60e8b
move to only checking b64
veerbia Nov 21, 2024
ec78781
Merge branch 'master' into veerbia/base64migration
veerbia Nov 21, 2024
49d5f88
replace appendformat in ContextPropagation.cs
veerbia Nov 22, 2024
a9da986
replace appendformat in tracer check
veerbia Nov 22, 2024
21577f7
rm semicolon
veerbia Nov 22, 2024
d186dee
rm log debug in DataStreamsManager.cs
veerbia Nov 22, 2024
dc3d43c
Extract Tracer.Instance to make testing easier
andrewlock Nov 22, 2024
166660c
Merge branch 'master' into veerbia/base64migration
veerbia Nov 22, 2024
1c8c29b
try to resolve null ptr exception
veerbia Nov 22, 2024
bec777b
Update snapshots for SQS
bouwkast Nov 22, 2024
be18958
Remove DSM JSON injection
bouwkast Nov 23, 2024
47d92fe
Set IsDataStreamsLegacyHeadersEnabled
bouwkast Nov 23, 2024
f48d1dd
Remove duplicate `PropagationKey` header
bouwkast Nov 23, 2024
6e9062a
Update tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S…
andrewlock Nov 25, 2024
5087d70
add option to enable/disable legacy headers for dsm tests
veerbia Dec 12, 2024
d84eb96
Merge commit '5087d7098f4c755637620fe680704dd3d4d95e10' into veerbia/…
veerbia Dec 16, 2024
381f958
rm immutabletracersettings.cs
veerbia Dec 16, 2024
1f9df68
Merge branch 'master' into veerbia/dsm-base64-migration
veerbia Dec 16, 2024
95a8651
fix rabbitmq tests
veerbia Dec 16, 2024
6c686f4
fix kafka tests
veerbia Dec 16, 2024
1aaa925
revert kafka tests
veerbia Dec 16, 2024
9ef5bd8
fix kafka tests to involve minimal changes
veerbia Dec 16, 2024
4c7e223
Merge branch 'master' into veerbia/dsm-base64-migration
veerbia Dec 16, 2024
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
7 changes: 7 additions & 0 deletions tracer/src/Datadog.Trace/Configuration/ConfigurationKeys.cs
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,13 @@ internal static class DataStreamsMonitoring
/// </summary>
/// <see cref="TracerSettings.IsDataStreamsMonitoringEnabled"/>
public const string Enabled = "DD_DATA_STREAMS_ENABLED";

/// <summary>
/// Configuration key for enabling legacy binary headers in Data Streams Monitoring.
/// Default is true.
/// </summary>
/// <see cref="TracerSettings.IsDataStreamsLegacyHeadersEnabled"/>
public const string LegacyHeadersEnabled = "DD_DATA_STREAMS_LEGACY_HEADERS";
}
}
}
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 @@ -520,6 +520,10 @@ _ when x.ToBoolean() is { } boolean => boolean,
.WithKeys(ConfigurationKeys.DataStreamsMonitoring.Enabled)
.AsBool(false);

IsDataStreamsLegacyHeadersEnabled = config
.WithKeys(ConfigurationKeys.DataStreamsMonitoring.LegacyHeadersEnabled)
.AsBool(true);

IsRareSamplerEnabled = config
.WithKeys(ConfigurationKeys.RareSamplerEnabled)
.AsBool(false);
Expand Down Expand Up @@ -985,6 +989,11 @@ public bool DiagnosticSourceEnabled
/// </summary>
internal bool IsDataStreamsMonitoringEnabled => DynamicSettings.DataStreamsMonitoringEnabled ?? _isDataStreamsMonitoringEnabled;

/// <summary>
/// Gets a value indicating whether to inject legacy binary headers for Data Streams.
/// </summary>
internal bool IsDataStreamsLegacyHeadersEnabled { 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 @@ -2,13 +2,14 @@
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

#nullable enable

using System;
using System.Text;
using Datadog.Trace.Headers;
using Datadog.Trace.Logging;
using Datadog.Trace.Util;
using Datadog.Trace.VendoredMicrosoftCode.System.Buffers;
using Datadog.Trace.VendoredMicrosoftCode.System.Buffers.Text;

namespace Datadog.Trace.DataStreamsMonitoring;

Expand All @@ -17,6 +18,8 @@ namespace Datadog.Trace.DataStreamsMonitoring;
/// </summary>
internal class DataStreamsContextPropagator
{
private static readonly IDatadogLogger Log = DatadogLogging.GetLoggerFor<DataStreamsContextPropagator>();

public static DataStreamsContextPropagator Instance { get; } = new();

/// <summary>
Expand All @@ -28,10 +31,42 @@ internal class DataStreamsContextPropagator
/// <typeparam name="TCarrier">Type of header collection</typeparam>
public void Inject<TCarrier>(PathwayContext context, TCarrier headers)
where TCarrier : IBinaryHeadersCollection
=> Inject(context, headers, Tracer.Instance.Settings.IsDataStreamsLegacyHeadersEnabled);

// Internal for testing
internal void Inject<TCarrier>(PathwayContext context, TCarrier headers, bool isDataStreamsLegacyHeadersEnabled)
where TCarrier : IBinaryHeadersCollection
{
if (headers is null) { ThrowHelper.ThrowArgumentNullException(nameof(headers)); }

headers.Add(DataStreamsPropagationHeaders.PropagationKey, PathwayContextEncoder.Encode(context));
var encodedBytes = PathwayContextEncoder.Encode(context);

// Calculate the maximum length of the base64 encoded data
// Base64 encoding encodes 3 bytes of data into 4 bytes of encoded data
// So the maximum length is ceil(encodedBytes.Length / 3) * 4 and using integer arithmetic it's ((encodedBytes.Length + 2) / 3) * 4
int base64Length = ((encodedBytes.Length + 2) / 3) * 4;
byte[] base64EncodedContextBytes = new byte[base64Length];
var status = Base64.EncodeToUtf8(encodedBytes, base64EncodedContextBytes, out _, out int bytesWritten);

if (status != OperationStatus.Done)
{
Log.Error("Failed to encode Data Streams context to Base64. OperationStatus: {Status}", status);
return;
}

if (bytesWritten == base64EncodedContextBytes.Length)
{
headers.Add(DataStreamsPropagationHeaders.PropagationKeyBase64, base64EncodedContextBytes);
}
else
{
headers.Add(DataStreamsPropagationHeaders.PropagationKeyBase64, base64EncodedContextBytes.AsSpan(0, bytesWritten).ToArray());
}

if (isDataStreamsLegacyHeadersEnabled)
{
headers.Add(DataStreamsPropagationHeaders.PropagationKey, encodedBytes);
}
}

/// <summary>
Expand All @@ -42,12 +77,68 @@ public void Inject<TCarrier>(PathwayContext context, TCarrier headers)
/// <returns>A new <see cref="PathwayContext"/> that contains the values obtained from <paramref name="headers"/>.</returns>
public PathwayContext? Extract<TCarrier>(TCarrier headers)
where TCarrier : IBinaryHeadersCollection
=> Extract(headers, Tracer.Instance.Settings.IsDataStreamsLegacyHeadersEnabled);

// internal for testing
internal PathwayContext? Extract<TCarrier>(TCarrier headers, bool isDataStreamsLegacyHeadersEnabled)
where TCarrier : IBinaryHeadersCollection
{
if (headers is null) { ThrowHelper.ThrowArgumentNullException(nameof(headers)); }

var bytes = headers.TryGetLastBytes(DataStreamsPropagationHeaders.PropagationKey);
// Try to extract from the base64 header first
var base64Bytes = headers.TryGetLastBytes(DataStreamsPropagationHeaders.PropagationKeyBase64);
if (base64Bytes is { Length: > 0 })
{
try
{
// Calculate the maximum decoded length
// Base64 encoding encodes 3 bytes of data into 4 bytes of encoded data
// So the maximum decoded length is (base64Bytes.Length * 3) / 4
int decodedLength = (base64Bytes.Length * 3) / 4;
byte[] decodedBytes = new byte[decodedLength];

var status = Base64.DecodeFromUtf8(base64Bytes, decodedBytes, out _, out int bytesWritten);

if (status != OperationStatus.Done)
{
Log.Error("Failed to decode Base64 data streams context. OperationStatus: {Status}", status);
return null;
}
else
{
if (bytesWritten == decodedBytes.Length)
{
return PathwayContextEncoder.Decode(decodedBytes);
}
else
{
return PathwayContextEncoder.Decode(decodedBytes.AsSpan(0, bytesWritten).ToArray());
}
}
}
catch (Exception ex)
{
Log.Error(ex, "Failed to decode base64 Data Streams context.");
}
}

return bytes is { } ? PathwayContextEncoder.Decode(bytes) : null;
if (isDataStreamsLegacyHeadersEnabled)
{
var binaryBytes = headers.TryGetLastBytes(DataStreamsPropagationHeaders.PropagationKey);
if (binaryBytes is { Length: > 0 })
{
try
{
return PathwayContextEncoder.Decode(binaryBytes);
}
catch (Exception ex)
{
Log.Error(ex, "Failed to decode binary Data Streams context.");
}
}
}

return null;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,21 +83,12 @@ public async Task DisposeAsync()
public void InjectPathwayContext<TCarrier>(PathwayContext? context, TCarrier headers)
where TCarrier : IBinaryHeadersCollection
{
if (!IsEnabled)
{
return;
}

if (context is not null)
if (!IsEnabled || context is null)
{
DataStreamsContextPropagator.Instance.Inject(context.Value, headers);
return;
}

// This shouldn't happen normally, as you should call SetCheckpoint before calling InjectPathwayContext
// But if data streams was disabled, you call SetCheckpoint, and then data streams is enabled
// you will hit this code path
Log.Debug("Attempted to inject null pathway context");
DataStreamsContextPropagator.Instance.Inject(context.Value, headers);
}

public void TrackBacklog(string tags, long value)
Expand Down
3 changes: 3 additions & 0 deletions tracer/src/Datadog.Trace/TracerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,9 @@ void WriteDictionary(IReadOnlyDictionary<string, string> dictionary)
writer.WritePropertyName("data_streams_enabled");
writer.WriteValue(instanceSettings.IsDataStreamsMonitoringEnabled);

writer.WritePropertyName("data_streams_legacy_headers_enabled");
writer.WriteValue(instanceSettings.IsDataStreamsLegacyHeadersEnabled);

writer.WritePropertyName("span_sampling_rules");
writer.WriteValue(instanceSettings.SpanSamplingRules);

Expand Down
Loading
Loading