diff --git a/src/Components/Aspire.RabbitMQ.Client/README.md b/src/Components/Aspire.RabbitMQ.Client/README.md index 42176b27cf7..0e05bba694e 100644 --- a/src/Components/Aspire.RabbitMQ.Client/README.md +++ b/src/Components/Aspire.RabbitMQ.Client/README.md @@ -18,7 +18,7 @@ dotnet add package Aspire.RabbitMQ.Client ## Usage example -In the _AppHost.cs_ file of your project, call the `AddRabbitMQClient` extension method to register an `IConnection` for use via the dependency injection container. The method takes a connection name parameter. +In the _Program.cs_ file of your project, call the `AddRabbitMQClient` extension method to register an `IConnection` for use via the dependency injection container. The method takes a connection name parameter. ```csharp builder.AddRabbitMQClient("messaging"); diff --git a/src/Components/Telemetry.md b/src/Components/Telemetry.md index f9b43d7037a..d8f6aa7f873 100644 --- a/src/Components/Telemetry.md +++ b/src/Components/Telemetry.md @@ -362,7 +362,9 @@ Aspire.RabbitMQ.Client: - Log categories: - "RabbitMQ.Client" - Activity source names: - - "Aspire.RabbitMQ.Client" + - "Aspire.RabbitMQ.Client" (connection establishment and retry attempts) + - "RabbitMQ.Client.Publisher" (message publishing operations; RabbitMQ.Client v7+ only) + - "RabbitMQ.Client.Subscriber" (message consumption operations; RabbitMQ.Client v7+ only) - Metric names: - none (currently not supported by RabbitMQ.Client library) diff --git a/tests/Aspire.RabbitMQ.Client.Tests/ConformanceTests.cs b/tests/Aspire.RabbitMQ.Client.Tests/ConformanceTests.cs index 1f60d365010..390ddd56990 100644 --- a/tests/Aspire.RabbitMQ.Client.Tests/ConformanceTests.cs +++ b/tests/Aspire.RabbitMQ.Client.Tests/ConformanceTests.cs @@ -9,15 +9,25 @@ using RabbitMQ.Client; using Xunit; +#if !RABBITMQ_V6 +using System.Diagnostics; +using Microsoft.Extensions.Logging; +using OpenTelemetry.Trace; +#endif + namespace Aspire.RabbitMQ.Client.Tests; public class ConformanceTests : ConformanceTests, IClassFixture { - private readonly RabbitMQContainerFixture _containerFixture; + private readonly RabbitMQContainerFixture? _containerFixture; + private string ConnectionString { get; set; } - public ConformanceTests(RabbitMQContainerFixture containerFixture, ITestOutputHelper? output = null) : base(output) + public ConformanceTests(RabbitMQContainerFixture? containerFixture, ITestOutputHelper? output = null) : base(output) { _containerFixture = containerFixture; + ConnectionString = (_containerFixture is not null && RequiresFeatureAttribute.IsFeatureSupported(TestFeature.Docker)) + ? _containerFixture.GetConnectionString() + : "amqp://localhost:5672"; } protected override ServiceLifetime ServiceLifetime => ServiceLifetime.Singleton; @@ -31,7 +41,11 @@ public ConformanceTests(RabbitMQContainerFixture containerFixture, ITestOutputHe protected override string[] RequiredLogCategories => Array.Empty(); - protected override string ActivitySourceName => ""; +#if RABBITMQ_V6 + protected override string ActivitySourceName => "Aspire.RabbitMQ.Client"; +#else + protected override string ActivitySourceName => "RabbitMQ.Client.Publisher"; +#endif protected override string? ConfigurationSectionName => "Aspire:RabbitMQ:Client"; @@ -69,15 +83,9 @@ protected override (string json, string error)[] InvalidJsonToErrorMessage => ne }; protected override void PopulateConfiguration(ConfigurationManager configuration, string? key = null) - { - var connectionString = RequiresFeatureAttribute.IsFeatureSupported(TestFeature.Docker) ? - _containerFixture.GetConnectionString() : - "amqp://localhost:5672"; - - configuration.AddInMemoryCollection([ - new(CreateConfigKey("Aspire:RabbitMQ:Client", key, "ConnectionString"), connectionString) + => configuration.AddInMemoryCollection([ + new(CreateConfigKey("Aspire:RabbitMQ:Client", key, "ConnectionString"), ConnectionString) ]); - } protected override void RegisterComponent(HostApplicationBuilder builder, Action? configure = null, string? key = null) { @@ -132,4 +140,48 @@ protected override void SetupConnectionInformationIsDelayValidated() { Assert.Skip("RabbitMQ connects to localhost by default if the connection information isn't available."); } + +#if !RABBITMQ_V6 + [Fact] + [RequiresFeature(TestFeature.Docker)] + public void TracingEnablesTheRightActivitySource() + => RemoteInvokeWithLogging(static connectionStringToUse => + RunWithConnectionString(connectionStringToUse, static obj => obj.RunActivitySourceTest(key: null)), + ConnectionString, Output); + + [Fact] + [RequiresFeature(TestFeature.Docker)] + public void TracingEnablesTheRightActivitySource_Keyed() + => RemoteInvokeWithLogging(static connectionStringToUse => + RunWithConnectionString(connectionStringToUse, static obj => obj.RunActivitySourceTest(key: "key")), + ConnectionString, Output); + + private void RunActivitySourceTest(string? key) + { + HostApplicationBuilder builder = CreateHostBuilder(key: key); + builder.Logging.AddConsole(); + RegisterComponent(builder, options => SetTracing(options, true), key); + + List exportedActivities = []; + builder.Services.AddOpenTelemetry().WithTracing(traceBuilder => traceBuilder.AddInMemoryExporter(exportedActivities)); + + using IHost host = builder.Build(); + host.Start(); + + IConnection service = key is null + ? host.Services.GetRequiredService() + : host.Services.GetRequiredKeyedService(key); + + // Clear activities generated during connection establishment (from "Aspire.RabbitMQ.Client" source) + exportedActivities.Clear(); + + TriggerActivity(service); + + Assert.NotEmpty(exportedActivities); + Assert.Contains(exportedActivities, activity => activity.Source.Name == ActivitySourceName); + } + + private static void RunWithConnectionString(string connectionString, Action test) + => test(new ConformanceTests(null) { ConnectionString = connectionString }); +#endif }