diff --git a/projects/RabbitMQ.Client.OpenTelemetry/PublicAPI.Unshipped.txt b/projects/RabbitMQ.Client.OpenTelemetry/PublicAPI.Unshipped.txt index e69de29bb..2321846d1 100644 --- a/projects/RabbitMQ.Client.OpenTelemetry/PublicAPI.Unshipped.txt +++ b/projects/RabbitMQ.Client.OpenTelemetry/PublicAPI.Unshipped.txt @@ -0,0 +1 @@ +~static OpenTelemetry.Trace.OpenTelemetryExtensions.AddRabbitMQInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder builder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/projects/RabbitMQ.Client.OpenTelemetry/TraceProviderBuilderExtensions.cs b/projects/RabbitMQ.Client.OpenTelemetry/TraceProviderBuilderExtensions.cs index 2e823219a..643c8f023 100644 --- a/projects/RabbitMQ.Client.OpenTelemetry/TraceProviderBuilderExtensions.cs +++ b/projects/RabbitMQ.Client.OpenTelemetry/TraceProviderBuilderExtensions.cs @@ -8,16 +8,26 @@ namespace OpenTelemetry.Trace { + public static class OpenTelemetryExtensions { - public static TracerProviderBuilder AddRabbitMQInstrumentation(this TracerProviderBuilder builder) + public static TracerProviderBuilder AddRabbitMQInstrumentation(this TracerProviderBuilder builder, Action configure) { + var options = new RabbitMQTracingOptions(); + configure?.Invoke(options); + RabbitMQActivitySource.TracingOptions = options; + RabbitMQActivitySource.ContextExtractor = OpenTelemetryContextExtractor; RabbitMQActivitySource.ContextInjector = OpenTelemetryContextInjector; builder.AddSource("RabbitMQ.Client.*"); return builder; } + public static TracerProviderBuilder AddRabbitMQInstrumentation(this TracerProviderBuilder builder) + { + return AddRabbitMQInstrumentation(builder, null); + } + private static ActivityContext OpenTelemetryContextExtractor(IReadOnlyBasicProperties props) { // Extract the PropagationContext of the upstream parent from the message headers. diff --git a/projects/RabbitMQ.Client/Impl/RabbitMQActivitySource.cs b/projects/RabbitMQ.Client/Impl/RabbitMQActivitySource.cs index 31d076cbd..764828ce3 100644 --- a/projects/RabbitMQ.Client/Impl/RabbitMQActivitySource.cs +++ b/projects/RabbitMQ.Client/Impl/RabbitMQActivitySource.cs @@ -51,7 +51,12 @@ public static class RabbitMQActivitySource public static Func ContextExtractor { get; set; } = DefaultContextExtractor; - public static bool UseRoutingKeyAsOperationName { get; set; } = true; + public static bool UseRoutingKeyAsOperationName + { + get => TracingOptions.UseRoutingKeyAsOperationName; + set => TracingOptions.UseRoutingKeyAsOperationName = value; + } + public static RabbitMQTracingOptions TracingOptions { get; set; } = new RabbitMQTracingOptions(); internal static bool PublisherHasListeners => s_publisherSource.HasListeners(); internal static readonly IEnumerable> CreationTags = new[] @@ -115,9 +120,14 @@ public static class RabbitMQActivitySource } // Extract the PropagationContext of the upstream parent from the message headers. + ActivityContext linkedContext = ContextExtractor(readOnlyBasicProperties); + ActivityContext parentContext = TracingOptions.UsePublisherAsParent ? linkedContext : default; + Activity? activity = s_subscriberSource.StartLinkedRabbitMQActivity( UseRoutingKeyAsOperationName ? $"{MessagingOperationNameBasicGet} {routingKey}" : MessagingOperationNameBasicGet, ActivityKind.Consumer, - ContextExtractor(readOnlyBasicProperties)); + linkedContext, parentContext); + + if (activity != null && activity.IsAllDataRequested) { PopulateMessagingTags(MessagingOperationTypeReceive, MessagingOperationNameBasicGet, routingKey, exchange, deliveryTag, readOnlyBasicProperties, @@ -128,7 +138,7 @@ public static class RabbitMQActivitySource } internal static Activity? Deliver(string routingKey, string exchange, ulong deliveryTag, - IReadOnlyBasicProperties basicProperties, int bodySize) + IReadOnlyBasicProperties readOnlyBasicProperties, int bodySize) { if (!s_subscriberSource.HasListeners()) { @@ -136,13 +146,16 @@ public static class RabbitMQActivitySource } // Extract the PropagationContext of the upstream parent from the message headers. + ActivityContext linkedContext = ContextExtractor(readOnlyBasicProperties); + ActivityContext parentContext = TracingOptions.UsePublisherAsParent ? linkedContext : default; + Activity? activity = s_subscriberSource.StartLinkedRabbitMQActivity( UseRoutingKeyAsOperationName ? $"{MessagingOperationNameBasicDeliver} {routingKey}" : MessagingOperationNameBasicDeliver, - ActivityKind.Consumer, ContextExtractor(basicProperties)); + ActivityKind.Consumer, linkedContext, parentContext); if (activity != null && activity.IsAllDataRequested) { PopulateMessagingTags(MessagingOperationTypeProcess, MessagingOperationNameBasicDeliver, routingKey, exchange, - deliveryTag, basicProperties, bodySize, activity); + deliveryTag, readOnlyBasicProperties, bodySize, activity); } return activity; @@ -157,8 +170,14 @@ public static class RabbitMQActivitySource private static Activity? StartLinkedRabbitMQActivity(this ActivitySource source, string name, ActivityKind kind, ActivityContext linkedContext = default, ActivityContext parentContext = default) { + List? links = null; + if (linkedContext != default) + { + links = new List(); + links.Add(new ActivityLink(linkedContext)); + } return source.CreateActivity(name, kind, parentContext: parentContext, - links: new[] { new ActivityLink(linkedContext) }, idFormat: ActivityIdFormat.W3C, + links: links, idFormat: ActivityIdFormat.W3C, tags: CreationTags) ?.Start(); } diff --git a/projects/RabbitMQ.Client/Impl/RabbitMQTracingOptions.cs b/projects/RabbitMQ.Client/Impl/RabbitMQTracingOptions.cs new file mode 100644 index 000000000..cc2d7268b --- /dev/null +++ b/projects/RabbitMQ.Client/Impl/RabbitMQTracingOptions.cs @@ -0,0 +1,8 @@ +namespace RabbitMQ.Client +{ + public class RabbitMQTracingOptions + { + public bool UseRoutingKeyAsOperationName { get; set; } = true; + public bool UsePublisherAsParent { get; set; } = true; + } +} diff --git a/projects/RabbitMQ.Client/PublicAPI.Unshipped.txt b/projects/RabbitMQ.Client/PublicAPI.Unshipped.txt index 9a4615009..b78bae4b2 100644 --- a/projects/RabbitMQ.Client/PublicAPI.Unshipped.txt +++ b/projects/RabbitMQ.Client/PublicAPI.Unshipped.txt @@ -4,4 +4,12 @@ RabbitMQ.Client.Exceptions.PublishReturnException.Exchange.get -> string! RabbitMQ.Client.Exceptions.PublishReturnException.PublishReturnException(ulong publishSequenceNumber, string! message, string? exchange = null, string? routingKey = null, ushort? replyCode = null, string? replyText = null) -> void RabbitMQ.Client.Exceptions.PublishReturnException.ReplyCode.get -> ushort RabbitMQ.Client.Exceptions.PublishReturnException.ReplyText.get -> string! -RabbitMQ.Client.Exceptions.PublishReturnException.RoutingKey.get -> string! \ No newline at end of file +RabbitMQ.Client.Exceptions.PublishReturnException.RoutingKey.get -> string! +RabbitMQ.Client.RabbitMQTracingOptions +RabbitMQ.Client.RabbitMQTracingOptions.RabbitMQTracingOptions() -> void +RabbitMQ.Client.RabbitMQTracingOptions.UsePublisherAsParent.get -> bool +RabbitMQ.Client.RabbitMQTracingOptions.UsePublisherAsParent.set -> void +RabbitMQ.Client.RabbitMQTracingOptions.UseRoutingKeyAsOperationName.get -> bool +RabbitMQ.Client.RabbitMQTracingOptions.UseRoutingKeyAsOperationName.set -> void +static RabbitMQ.Client.RabbitMQActivitySource.TracingOptions.get -> RabbitMQ.Client.RabbitMQTracingOptions! +static RabbitMQ.Client.RabbitMQActivitySource.TracingOptions.set -> void diff --git a/projects/Test/SequentialIntegration/TestActivitySource.cs b/projects/Test/SequentialIntegration/TestActivitySource.cs index af84b39e7..6591638ce 100644 --- a/projects/Test/SequentialIntegration/TestActivitySource.cs +++ b/projects/Test/SequentialIntegration/TestActivitySource.cs @@ -76,11 +76,14 @@ void AssertIntTagGreaterThanZero(Activity activity, string name) } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task TestPublisherAndConsumerActivityTags(bool useRoutingKeyAsOperationName) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task TestPublisherAndConsumerActivityTags(bool useRoutingKeyAsOperationName, bool usePublisherAsParent) { RabbitMQActivitySource.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; + RabbitMQActivitySource.TracingOptions.UsePublisherAsParent = usePublisherAsParent; var _activities = new List(); using ActivityListener activityListener = StartActivityListener(_activities); await Task.Delay(500); @@ -106,15 +109,18 @@ public async Task TestPublisherAndConsumerActivityTags(bool useRoutingKeyAsOpera await _channel.BasicCancelAsync(consumerTag); await Task.Delay(500); - AssertActivityData(useRoutingKeyAsOperationName, queueName, _activities, true); + AssertActivityData(useRoutingKeyAsOperationName, usePublisherAsParent, queueName, _activities, true); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task TestPublisherWithCachedStringsAndConsumerActivityTags(bool useRoutingKeyAsOperationName) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task TestPublisherWithCachedStringsAndConsumerActivityTags(bool useRoutingKeyAsOperationName, bool usePublisherAsParent) { RabbitMQActivitySource.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; + RabbitMQActivitySource.TracingOptions.UsePublisherAsParent = usePublisherAsParent; var _activities = new List(); using ActivityListener activityListener = StartActivityListener(_activities); await Task.Delay(500); @@ -142,15 +148,18 @@ public async Task TestPublisherWithCachedStringsAndConsumerActivityTags(bool use await _channel.BasicCancelAsync(consumerTag); await Task.Delay(500); - AssertActivityData(useRoutingKeyAsOperationName, queueName, _activities, true); + AssertActivityData(useRoutingKeyAsOperationName, usePublisherAsParent, queueName, _activities, true); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task TestPublisherWithPublicationAddressAndConsumerActivityTags(bool useRoutingKeyAsOperationName) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task TestPublisherWithPublicationAddressAndConsumerActivityTags(bool useRoutingKeyAsOperationName, bool usePublisherAsParent) { RabbitMQActivitySource.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; + RabbitMQActivitySource.TracingOptions.UsePublisherAsParent = usePublisherAsParent; var _activities = new List(); using ActivityListener activityListener = StartActivityListener(_activities); await Task.Delay(500); @@ -177,15 +186,18 @@ public async Task TestPublisherWithPublicationAddressAndConsumerActivityTags(boo await _channel.BasicCancelAsync(consumerTag); await Task.Delay(500); - AssertActivityData(useRoutingKeyAsOperationName, queueName, _activities, true); + AssertActivityData(useRoutingKeyAsOperationName, usePublisherAsParent, queueName, _activities, true); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task TestPublisherAndConsumerActivityTagsAsync(bool useRoutingKeyAsOperationName) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task TestPublisherAndConsumerActivityTagsAsync(bool useRoutingKeyAsOperationName, bool usePublisherAsParent) { RabbitMQActivitySource.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; + RabbitMQActivitySource.TracingOptions.UsePublisherAsParent = usePublisherAsParent; var activities = new List(); using ActivityListener activityListener = StartActivityListener(activities); await Task.Delay(500); @@ -212,15 +224,18 @@ public async Task TestPublisherAndConsumerActivityTagsAsync(bool useRoutingKeyAs await _channel.BasicCancelAsync(consumerTag); await Task.Delay(500); - AssertActivityData(useRoutingKeyAsOperationName, queueName, activities, true); + AssertActivityData(useRoutingKeyAsOperationName, usePublisherAsParent, queueName, activities, true); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task TestPublisherWithCachedStringsAndConsumerActivityTagsAsync(bool useRoutingKeyAsOperationName) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task TestPublisherWithCachedStringsAndConsumerActivityTagsAsync(bool useRoutingKeyAsOperationName, bool usePublisherAsParent) { RabbitMQActivitySource.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; + RabbitMQActivitySource.TracingOptions.UsePublisherAsParent = usePublisherAsParent; var activities = new List(); using ActivityListener activityListener = StartActivityListener(activities); await Task.Delay(500); @@ -249,15 +264,18 @@ public async Task TestPublisherWithCachedStringsAndConsumerActivityTagsAsync(boo await _channel.BasicCancelAsync(consumerTag); await Task.Delay(500); - AssertActivityData(useRoutingKeyAsOperationName, queueName, activities, true); + AssertActivityData(useRoutingKeyAsOperationName, usePublisherAsParent, queueName, activities, true); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task TestPublisherWithPublicationAddressAndConsumerActivityTagsAsync(bool useRoutingKeyAsOperationName) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task TestPublisherWithPublicationAddressAndConsumerActivityTagsAsync(bool useRoutingKeyAsOperationName, bool usePublisherAsParent) { RabbitMQActivitySource.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; + RabbitMQActivitySource.TracingOptions.UsePublisherAsParent = usePublisherAsParent; var activities = new List(); using ActivityListener activityListener = StartActivityListener(activities); await Task.Delay(500); @@ -285,15 +303,18 @@ public async Task TestPublisherWithPublicationAddressAndConsumerActivityTagsAsyn await _channel.BasicCancelAsync(consumerTag); await Task.Delay(500); - AssertActivityData(useRoutingKeyAsOperationName, queueName, activities, true); + AssertActivityData(useRoutingKeyAsOperationName, usePublisherAsParent, queueName, activities, true); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task TestPublisherAndBasicGetActivityTags(bool useRoutingKeyAsOperationName) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task TestPublisherAndBasicGetActivityTags(bool useRoutingKeyAsOperationName, bool usePublisherAsParent) { RabbitMQActivitySource.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; + RabbitMQActivitySource.TracingOptions.UsePublisherAsParent = usePublisherAsParent; var activities = new List(); using ActivityListener activityListener = StartActivityListener(activities); await Task.Delay(500); @@ -311,7 +332,7 @@ public async Task TestPublisherAndBasicGetActivityTags(bool useRoutingKeyAsOpera ok = await _channel.QueueDeclarePassiveAsync(queue); Assert.Equal(0u, ok.MessageCount); await Task.Delay(500); - AssertActivityData(useRoutingKeyAsOperationName, queue, activities, false); + AssertActivityData(useRoutingKeyAsOperationName, usePublisherAsParent, queue, activities, false); } finally { @@ -320,11 +341,14 @@ public async Task TestPublisherAndBasicGetActivityTags(bool useRoutingKeyAsOpera } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task TestPublisherWithCachedStringsAndBasicGetActivityTags(bool useRoutingKeyAsOperationName) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task TestPublisherWithCachedStringsAndBasicGetActivityTags(bool useRoutingKeyAsOperationName, bool usePublisherAsParent) { RabbitMQActivitySource.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; + RabbitMQActivitySource.TracingOptions.UsePublisherAsParent = usePublisherAsParent; var activities = new List(); using ActivityListener activityListener = StartActivityListener(activities); await Task.Delay(500); @@ -344,7 +368,7 @@ public async Task TestPublisherWithCachedStringsAndBasicGetActivityTags(bool use ok = await _channel.QueueDeclarePassiveAsync(queue); Assert.Equal(0u, ok.MessageCount); await Task.Delay(500); - AssertActivityData(useRoutingKeyAsOperationName, queue, activities, false); + AssertActivityData(useRoutingKeyAsOperationName, usePublisherAsParent, queue, activities, false); } finally { @@ -353,11 +377,14 @@ public async Task TestPublisherWithCachedStringsAndBasicGetActivityTags(bool use } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task TestPublisherWithPublicationAddressAndBasicGetActivityTags(bool useRoutingKeyAsOperationName) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task TestPublisherWithPublicationAddressAndBasicGetActivityTags(bool useRoutingKeyAsOperationName, bool usePublisherAsParent) { RabbitMQActivitySource.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; + RabbitMQActivitySource.TracingOptions.UsePublisherAsParent = usePublisherAsParent; var activities = new List(); using ActivityListener activityListener = StartActivityListener(activities); await Task.Delay(500); @@ -377,7 +404,7 @@ public async Task TestPublisherWithPublicationAddressAndBasicGetActivityTags(boo ok = await _channel.QueueDeclarePassiveAsync(queue); Assert.Equal(0u, ok.MessageCount); await Task.Delay(500); - AssertActivityData(useRoutingKeyAsOperationName, queue, activities, false); + AssertActivityData(useRoutingKeyAsOperationName, usePublisherAsParent, queue, activities, false); } finally { @@ -399,7 +426,7 @@ private static ActivityListener StartActivityListener(List activities) return activityListener; } - private void AssertActivityData(bool useRoutingKeyAsOperationName, string queueName, + private void AssertActivityData(bool useRoutingKeyAsOperationName, bool usePublisherAsParent, string queueName, List activityList, bool isDeliver = false) { string childName = isDeliver ? "deliver" : "fetch"; @@ -422,11 +449,20 @@ private void AssertActivityData(bool useRoutingKeyAsOperationName, string queueN x.GetTagItem(RabbitMQActivitySource.MessagingDestinationRoutingKey) is string routingKeyTag && routingKeyTag == $"{queueName}"); Activity receiveActivity = activities.Single(x => - x.OperationName == (useRoutingKeyAsOperationName ? $"{childName} {queueName}" : childName) && - x.Links.First().Context.TraceId == sendActivity.TraceId); + x.OperationName == (useRoutingKeyAsOperationName ? $"{childName} {queueName}" : childName)); Assert.Equal(ActivityKind.Producer, sendActivity.Kind); Assert.Equal(ActivityKind.Consumer, receiveActivity.Kind); - Assert.Null(receiveActivity.ParentId); + Assert.Equal(sendActivity.TraceId, receiveActivity.Links.Single().Context.TraceId); + if (usePublisherAsParent) + { + Assert.Equal(sendActivity.Id, receiveActivity.ParentId); + Assert.Equal(sendActivity.TraceId, receiveActivity.TraceId); + } + else + { + Assert.Null(receiveActivity.ParentId); + Assert.NotEqual(sendActivity.TraceId, receiveActivity.TraceId); + } AssertStringTagNotNullOrEmpty(sendActivity, "network.peer.address"); AssertStringTagNotNullOrEmpty(sendActivity, "network.local.address"); AssertStringTagNotNullOrEmpty(sendActivity, "server.address"); diff --git a/projects/Test/SequentialIntegration/TestOpenTelemetry.cs b/projects/Test/SequentialIntegration/TestOpenTelemetry.cs index 020c4ffd2..254c310b5 100644 --- a/projects/Test/SequentialIntegration/TestOpenTelemetry.cs +++ b/projects/Test/SequentialIntegration/TestOpenTelemetry.cs @@ -82,21 +82,38 @@ void AssertIntTagGreaterThanZero(Activity activity, string name) Assert.True(activity.GetTagItem(name) is int result && result > 0); } + [Fact] + public void TestDefaultTracingOptions() + { + using var tracer = Sdk.CreateTracerProviderBuilder() + .AddRabbitMQInstrumentation() + .Build(); + + Assert.True(RabbitMQActivitySource.UseRoutingKeyAsOperationName); + Assert.True(RabbitMQActivitySource.TracingOptions.UseRoutingKeyAsOperationName); + Assert.True(RabbitMQActivitySource.TracingOptions.UsePublisherAsParent); + } + [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task TestPublisherAndConsumerActivityTags(bool useRoutingKeyAsOperationName) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task TestPublisherAndConsumerActivityTags(bool useRoutingKeyAsOperationName, bool usePublisherAsParent) { var exportedItems = new List(); using var tracer = Sdk.CreateTracerProviderBuilder() - .AddRabbitMQInstrumentation() + .AddRabbitMQInstrumentation(options => + { + options.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; + options.UsePublisherAsParent = usePublisherAsParent; + }) .AddInMemoryExporter(exportedItems) .Build(); string baggageGuid = Guid.NewGuid().ToString(); Baggage.SetBaggage("TestItem", baggageGuid); Assert.Equal(baggageGuid, Baggage.GetBaggage("TestItem")); - RabbitMQActivitySource.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; await Task.Delay(500); string queueName = $"{Guid.NewGuid()}"; QueueDeclareOk q = await _channel.QueueDeclareAsync(queueName); @@ -132,24 +149,29 @@ public async Task TestPublisherAndConsumerActivityTags(bool useRoutingKeyAsOpera await _channel.BasicCancelAsync(consumerTag); await Task.Delay(500); - AssertActivityData(useRoutingKeyAsOperationName, queueName, exportedItems, true); + AssertActivityData(useRoutingKeyAsOperationName, usePublisherAsParent, queueName, exportedItems, true); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task TestPublisherAndConsumerActivityTagsAsync(bool useRoutingKeyAsOperationName) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task TestPublisherAndConsumerActivityTagsAsync(bool useRoutingKeyAsOperationName, bool usePublisherAsParent) { var exportedItems = new List(); using var tracer = Sdk.CreateTracerProviderBuilder() - .AddRabbitMQInstrumentation() + .AddRabbitMQInstrumentation(options => + { + options.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; + options.UsePublisherAsParent = usePublisherAsParent; + }) .AddInMemoryExporter(exportedItems) .Build(); string baggageGuid = Guid.NewGuid().ToString(); Baggage.SetBaggage("TestItem", baggageGuid); Assert.Equal(baggageGuid, Baggage.GetBaggage("TestItem")); - RabbitMQActivitySource.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; await Task.Delay(500); string queueName = $"{Guid.NewGuid()}"; @@ -186,24 +208,29 @@ public async Task TestPublisherAndConsumerActivityTagsAsync(bool useRoutingKeyAs await _channel.BasicCancelAsync(consumerTag); await Task.Delay(500); - AssertActivityData(useRoutingKeyAsOperationName, queueName, exportedItems, true); + AssertActivityData(useRoutingKeyAsOperationName, usePublisherAsParent, queueName, exportedItems, true); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task TestPublisherWithPublicationAddressAndConsumerActivityTagsAsync(bool useRoutingKeyAsOperationName) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task TestPublisherWithPublicationAddressAndConsumerActivityTagsAsync(bool useRoutingKeyAsOperationName, bool usePublisherAsParent) { var exportedItems = new List(); using var tracer = Sdk.CreateTracerProviderBuilder() - .AddRabbitMQInstrumentation() + .AddRabbitMQInstrumentation(options => + { + options.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; + options.UsePublisherAsParent = usePublisherAsParent; + }) .AddInMemoryExporter(exportedItems) .Build(); string baggageGuid = Guid.NewGuid().ToString(); Baggage.SetBaggage("TestItem", baggageGuid); Assert.Equal(baggageGuid, Baggage.GetBaggage("TestItem")); - RabbitMQActivitySource.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; await Task.Delay(500); string queueName = $"{Guid.NewGuid()}"; @@ -241,24 +268,29 @@ public async Task TestPublisherWithPublicationAddressAndConsumerActivityTagsAsyn await _channel.BasicCancelAsync(consumerTag); await Task.Delay(500); - AssertActivityData(useRoutingKeyAsOperationName, queueName, exportedItems, true); + AssertActivityData(useRoutingKeyAsOperationName, usePublisherAsParent, queueName, exportedItems, true); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task TestPublisherWithCachedStringsAndConsumerActivityTagsAsync(bool useRoutingKeyAsOperationName) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task TestPublisherWithCachedStringsAndConsumerActivityTagsAsync(bool useRoutingKeyAsOperationName, bool usePublisherAsParent) { var exportedItems = new List(); using var tracer = Sdk.CreateTracerProviderBuilder() - .AddRabbitMQInstrumentation() + .AddRabbitMQInstrumentation(options => + { + options.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; + options.UsePublisherAsParent = usePublisherAsParent; + }) .AddInMemoryExporter(exportedItems) .Build(); string baggageGuid = Guid.NewGuid().ToString(); Baggage.SetBaggage("TestItem", baggageGuid); Assert.Equal(baggageGuid, Baggage.GetBaggage("TestItem")); - RabbitMQActivitySource.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; await Task.Delay(500); string queueName = $"{Guid.NewGuid()}"; @@ -297,23 +329,28 @@ public async Task TestPublisherWithCachedStringsAndConsumerActivityTagsAsync(boo await _channel.BasicCancelAsync(consumerTag); await Task.Delay(500); - AssertActivityData(useRoutingKeyAsOperationName, queueName, exportedItems, true); + AssertActivityData(useRoutingKeyAsOperationName, usePublisherAsParent, queueName, exportedItems, true); } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task TestPublisherAndBasicGetActivityTags(bool useRoutingKeyAsOperationName) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task TestPublisherAndBasicGetActivityTags(bool useRoutingKeyAsOperationName, bool usePublisherAsParent) { var exportedItems = new List(); using var tracer = Sdk.CreateTracerProviderBuilder() - .AddRabbitMQInstrumentation() + .AddRabbitMQInstrumentation(options => + { + options.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; + options.UsePublisherAsParent = usePublisherAsParent; + }) .AddInMemoryExporter(exportedItems) .Build(); string baggageGuid = Guid.NewGuid().ToString(); Baggage.SetBaggage("TestItem", baggageGuid); Assert.Equal(baggageGuid, Baggage.GetBaggage("TestItem")); - RabbitMQActivitySource.UseRoutingKeyAsOperationName = useRoutingKeyAsOperationName; await Task.Delay(500); string queue = $"queue-{Guid.NewGuid()}"; const string msg = "for basic.get"; @@ -331,7 +368,7 @@ public async Task TestPublisherAndBasicGetActivityTags(bool useRoutingKeyAsOpera ok = await _channel.QueueDeclarePassiveAsync(queue); Assert.Equal(0u, ok.MessageCount); await Task.Delay(500); - AssertActivityData(useRoutingKeyAsOperationName, queue, exportedItems, false); + AssertActivityData(useRoutingKeyAsOperationName, usePublisherAsParent, queue, exportedItems, false); } finally { @@ -339,7 +376,7 @@ public async Task TestPublisherAndBasicGetActivityTags(bool useRoutingKeyAsOpera } } - private void AssertActivityData(bool useRoutingKeyAsOperationName, string queueName, + private void AssertActivityData(bool useRoutingKeyAsOperationName, bool usePublisherAsParent, string queueName, List activityList, bool isDeliver = false, string baggageGuid = null) { string childName = isDeliver ? "deliver" : "fetch"; @@ -359,11 +396,20 @@ private void AssertActivityData(bool useRoutingKeyAsOperationName, string queueN x.GetTagItem(RabbitMQActivitySource.MessagingDestinationRoutingKey) is string routingKeyTag && routingKeyTag == $"{queueName}"); Activity receiveActivity = activities.Single(x => - x.OperationName == (useRoutingKeyAsOperationName ? $"{childName} {queueName}" : childName) && - x.Links.First().Context.TraceId == sendActivity.TraceId); + x.OperationName == (useRoutingKeyAsOperationName ? $"{childName} {queueName}" : childName)); Assert.Equal(ActivityKind.Producer, sendActivity.Kind); Assert.Equal(ActivityKind.Consumer, receiveActivity.Kind); - Assert.Null(receiveActivity.ParentId); + Assert.Equal(sendActivity.TraceId, receiveActivity.Links.Single().Context.TraceId); + if (usePublisherAsParent) + { + Assert.Equal(sendActivity.Id, receiveActivity.ParentId); + Assert.Equal(sendActivity.TraceId, receiveActivity.TraceId); + } + else + { + Assert.Null(receiveActivity.ParentId); + Assert.NotEqual(sendActivity.TraceId, receiveActivity.TraceId); + } AssertStringTagNotNullOrEmpty(sendActivity, "network.peer.address"); AssertStringTagNotNullOrEmpty(sendActivity, "network.local.address"); AssertStringTagNotNullOrEmpty(sendActivity, "server.address"); @@ -385,6 +431,7 @@ private void AssertActivityData(bool useRoutingKeyAsOperationName, string queueN AssertStringTagEquals(receiveActivity, RabbitMQActivitySource.MessagingOperationName, childName); AssertStringTagEquals(sendActivity, RabbitMQActivitySource.MessagingOperationType, "send"); AssertStringTagEquals(sendActivity, RabbitMQActivitySource.MessagingOperationName, "publish"); + } } }