Skip to content

Commit

Permalink
Ensure baggage gets copied with baggage prefix (#2220)
Browse files Browse the repository at this point in the history
* Ensure baggage gets copied with baggage prefix

This brings our agent in line with the wider agent specification on how
to implement baggage propagation

https://github.com/elastic/apm/blob/main/specs/agents/tracing-distributed-tracing.md#baggage-related-configuration

* update failing testS
  • Loading branch information
Mpdreamz authored Nov 16, 2023
1 parent 12fe83c commit 29490f2
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 17 deletions.
4 changes: 2 additions & 2 deletions src/Elastic.Apm/Api/Context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ namespace Elastic.Apm.Api
{
public class Context
{
private Lazy<Dictionary<string, string>> _custom = new Lazy<Dictionary<string, string>>();
private Lazy<Dictionary<string, string>> _custom = new();

[JsonConverter(typeof(CustomJsonConverter))]
public Dictionary<string, string> Custom => _custom.Value;

internal Lazy<LabelsDictionary> InternalLabels = new Lazy<LabelsDictionary>();
internal Lazy<LabelsDictionary> InternalLabels = new();

/// <summary>
/// <seealso cref="ShouldSerializeLabels" />
Expand Down
4 changes: 3 additions & 1 deletion src/Elastic.Apm/Model/Error.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ private void CheckAndCaptureBaggage()
if (!WildcardMatcher.IsAnyMatch(Configuration.BaggageToAttach, baggage.Key))
continue;

Context.InternalLabels.Value.Add(baggage.Key, baggage.Value);
var newKey = $"baggage.{baggage.Key}";
var labels = Context.InternalLabels.Value;
labels[newKey] = baggage.Value;
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/Elastic.Apm/Model/Span.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,10 @@ private void CheckAndCaptureBaggage()
if (!WildcardMatcher.IsAnyMatch(Configuration.BaggageToAttach, baggage.Key))
continue;

Otel ??= new OTel() { Attributes = new Dictionary<string, object>() };
Otel.Attributes.Add(baggage.Key, baggage.Value);
Otel ??= new OTel { Attributes = new Dictionary<string, object>() };

var newKey = $"baggage.{baggage.Key}";
Otel.Attributes[newKey] = baggage.Value;
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/Elastic.Apm/Model/Transaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,10 @@ private void CheckAndCaptureBaggage()
if (!WildcardMatcher.IsAnyMatch(Configuration.BaggageToAttach, baggage.Key))
continue;

Otel ??= new OTel() { Attributes = new Dictionary<string, object>() };
Otel.Attributes.Add(baggage.Key, baggage.Value);
Otel ??= new OTel { Attributes = new Dictionary<string, object>() };

var newKey = $"baggage.{baggage.Key}";
Otel.Attributes[newKey] = baggage.Value;
}
}

Expand Down
18 changes: 12 additions & 6 deletions test/Elastic.Apm.Tests/DistributedTracing/BaggageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using System.Collections.Generic;
using System.Diagnostics;
using Elastic.Apm.Api;
using Elastic.Apm.Tests.Utilities;
using FluentAssertions;
using Xunit;
Expand Down Expand Up @@ -41,14 +42,15 @@ public void CaptureBaggageWithDefaultConfig()
RunSample(agent);

payloadSender.FirstTransaction.Should().NotBeNull();
payloadSender.FirstTransaction.Otel.Attributes.Should().Contain(new KeyValuePair<string, object>("foo", "bar"));
payloadSender.FirstTransaction.Otel.Attributes.Should().Contain(new KeyValuePair<string, object>("baggage.foo", "bar"));

payloadSender.FirstSpan.Should().NotBeNull();
payloadSender.FirstSpan.Otel.Attributes.Should().Contain(new KeyValuePair<string, object>("foo", "bar"));
payloadSender.FirstSpan.Otel.Attributes.Should().Contain(new KeyValuePair<string, object>("baggage.foo", "bar"));
payloadSender.FirstSpan.Otel.Attributes.Should().NotContain(new KeyValuePair<string, object>("foo", "bar"));

payloadSender.FirstError.Should().NotBeNull();
payloadSender.FirstError.Context.InternalLabels.Should().NotBeNull();
payloadSender.FirstError.Context.InternalLabels.Value.Should().Contain(new KeyValuePair<string, string>("foo", "bar"));
payloadSender.FirstError.Context.InternalLabels.Value.Should().Contain(new KeyValuePair<string, string>("baggage.foo", "bar"));
}

/// <summary>
Expand All @@ -66,17 +68,21 @@ public void CaptureBaggageWithNonDefaultConfig()
RunSample(agent);

payloadSender.FirstTransaction.Should().NotBeNull();
payloadSender.FirstTransaction.Otel.Attributes.Should().Contain(new KeyValuePair<string, object>("foo", "bar"));
payloadSender.FirstTransaction.Otel.Attributes.Should().Contain(new KeyValuePair<string, object>("baggage.foo", "bar"));
payloadSender.FirstTransaction.Otel.Attributes.Should().NotContainKey("key1");
payloadSender.FirstTransaction.Otel.Attributes.Should().NotContainKey("baggage.key1");

payloadSender.FirstSpan.Should().NotBeNull();
payloadSender.FirstSpan.Otel.Attributes.Should().Contain(new KeyValuePair<string, object>("foo", "bar"));
payloadSender.FirstSpan.Otel.Attributes.Should().Contain(new KeyValuePair<string, object>("baggage.foo", "bar"));
payloadSender.FirstSpan.Otel.Attributes.Should().NotContainKey("key1");
payloadSender.FirstSpan.Otel.Attributes.Should().NotContainKey("baggage.key1");

payloadSender.FirstError.Should().NotBeNull();
payloadSender.FirstError.Context.InternalLabels.Should().NotBeNull();
payloadSender.FirstError.Context.InternalLabels.Value.Should().Contain(new KeyValuePair<string, string>("foo", "bar"));
payloadSender.FirstError.Context.InternalLabels.Value.Should().Contain(new KeyValuePair<string, string>("baggage.foo", "bar"));
payloadSender.FirstError.Context.InternalLabels.Value.Should().NotContainKey("key1");
payloadSender.FirstError.Context.InternalLabels.Value.Should().NotContainKey("foo");
payloadSender.FirstError.Context.InternalLabels.Value.Should().NotContainKey("baggage.key1");
}

private void RunSample(ApmAgent agent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Elastic.Apm.Model;
using FluentAssertions;
using Xunit;

Expand All @@ -14,6 +15,10 @@ namespace Elastic.Apm.AspNetCore.Tests;
[Collection("DiagnosticListenerTest")]
public class BaggageAspNetCoreTests : MultiApplicationTestBase
{

private void ValidateOtelAttribute(Transaction transaction, string key, string value) =>
transaction.Otel.Attributes.Should().Contain(new KeyValuePair<string, object>($"baggage.{key}", value));

[Fact]
public async Task AccessBaggageFromUpstream()
{
Expand All @@ -35,11 +40,12 @@ public async Task AccessBaggageFromUpstream()
.Should()
.Be("key1=value1, key2 = value2, key3=value3");

_payloadSender1.FirstTransaction.Otel.Attributes.Should().Contain(new KeyValuePair<string, object>("key1", "value1"));
_payloadSender1.FirstTransaction.Otel.Attributes.Should().Contain(new KeyValuePair<string, object>("key2", "value2"));
_payloadSender1.FirstTransaction.Otel.Attributes.Should().Contain(new KeyValuePair<string, object>("key3", "value3"));
ValidateOtelAttribute(_payloadSender1.FirstTransaction, "key1", "value1");
ValidateOtelAttribute(_payloadSender1.FirstTransaction, "key2", "value2");
ValidateOtelAttribute(_payloadSender1.FirstTransaction, "key3", "value3");
}


/// <summary>
/// Calls the 1. service without any baggage, the /Home/WriteBaggage endpoint in the 1. service adds a baggage and then
/// calls the 2. service as a downstream service.
Expand Down Expand Up @@ -73,6 +79,6 @@ public async Task MultipleServices()
.Should()
.Be("foo=bar");

_payloadSender2.FirstTransaction.Otel.Attributes.Should().Contain(new KeyValuePair<string, object>("foo", "bar"));
ValidateOtelAttribute(_payloadSender2.FirstTransaction, "foo", "bar");
}
}

0 comments on commit 29490f2

Please sign in to comment.