Skip to content
Merged
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 @@ -112,7 +112,7 @@ context by hand again.
Mechanically, `ActivityFactory` creates the incoming activity, forces the W3C id format, adds the tags and
starts it. Only then does it read the headers. `ContextPropagation.PropagateContextFromHeaders` is split
into `PropagateTraceStateFromHeaders(activity, headers)` and `PropagateBaggageFromHeaders(activity,
headers)`. The split applies to both propagator paths, including the legacy path in `obsolete_v11.cs`.
headers)`. The split applies to both propagator paths, including the legacy path in `obsoletes-v10.cs`.
Both methods expect a started activity. The combined method stays for callers that need both.

## Consequences
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public abstract class OpenTelemetryAcceptanceTest : NServiceBusAcceptanceTest
protected TestingActivityListener NServiceBusActivityListener { get; private set; }

[SetUp]
public void Setup() => NServiceBusActivityListener = TestingActivityListener.SetupDiagnosticListener("NServiceBus.Core", "NServiceBus.Core.Recoverability");
public void Setup() => NServiceBusActivityListener = TestingActivityListener.SetupDiagnosticListener("NServiceBus.Core", "NServiceBus.Core.Handler", "NServiceBus.Core.Recoverability");

[TearDown]
public void Cleanup()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public async Task Should_propagate_baggage_to_headers()

// Default (backwards-compatible) propagation produces the legacy comma-separated, percent-encoded format.
// The W3C OWS format ("key3 = , key2 = value2, key1 = value1") is produced only when the
// NServiceBus.Core.OpenTelemetry.UseDistributedContextPropagator AppContext switch is enabled (default in v11).
// NServiceBus.Core.OpenTelemetry.UseV11Behavior AppContext switch is enabled (the only behavior in v11).
Assert.That(context.BaggageHeader, Is.EqualTo("key3=,key2=value2,key1=value1"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,11 @@ public Task Handle(IncomingMessage message, IMessageHandlerContext context)
}

[Test]
public async Task Should_use_receive_address_in_span_name_when_opted_in()
[OpenTelemetryV11Defaults]
public async Task Should_include_receive_address_in_span_name()
{
await Scenario.Define<Context>()
.WithEndpoint<ReceivingEndpointWithDestinationNaming>(e => e
.WithEndpoint<ReceivingEndpoint>(e => e
.When(s => s.SendLocal(new IncomingMessage())))
.Run();

Expand All @@ -96,21 +97,5 @@ await Scenario.Define<Context>()
Assert.That(incomingActivity.DisplayName, Is.Not.EqualTo("process message"));
}

public class ReceivingEndpointWithDestinationNaming : EndpointConfigurationBuilder
{
public ReceivingEndpointWithDestinationNaming() =>
EndpointSetup<DefaultServer>(b => b.Tracing().UseMessageTypeNamesInSpanNames = true);

[Handler]
public class MessageHandler(Context testContext) : IHandleMessages<IncomingMessage>
{
public Task Handle(IncomingMessage message, IMessageHandlerContext context)
{
testContext.MarkAsCompleted();
return Task.CompletedTask;
}
}
}

public class IncomingMessage : IMessage;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class When_processing_message_with_default_activity_sources : OpenTelemet
{
// Until v11, handler spans are emitted from the "NServiceBus.Core" ActivitySource by default
// for backwards compatibility. The dedicated "NServiceBus.Core.Handler" source is opt-in via
// the NServiceBus.Core.OpenTelemetry.UseHandlerActivitySource AppContext switch (default in v11).
// the NServiceBus.Core.OpenTelemetry.UseV11Behavior AppContext switch (the only behavior in v11).
[Test]
public async Task Should_emit_handler_span_from_main_source()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,13 @@ public Task Handle(ThisIsAnEvent @event, IMessageHandlerContext context)
}

[Test]
public async Task Should_use_event_type_in_span_name_when_opted_in()
[OpenTelemetryV11Defaults]
public async Task Should_include_event_type_in_span_name()
{
await Scenario.Define<Context>()
.WithEndpoint<PublisherWithDestinationNaming>(b => b
.WithEndpoint<PublisherForV11Naming>(b => b
.When(ctx => ctx.SomeEventSubscribed, s => s.Publish<ThisIsAnEvent>()))
.WithEndpoint<SubscriberForPublisherWithDestinationNaming>(b => b.When((session, ctx) =>
.WithEndpoint<SubscriberForPublisherForV11Naming>(b => b.When((session, ctx) =>
{
if (ctx.HasNativePubSubSupport)
{
Expand All @@ -203,15 +204,14 @@ await Scenario.Define<Context>()
Assert.That(publishedMessage.DisplayName, Is.EqualTo("publish ThisIsAnEvent"));
}

public class PublisherWithDestinationNaming : EndpointConfigurationBuilder
public class PublisherForV11Naming : EndpointConfigurationBuilder
{
public PublisherWithDestinationNaming() =>
public PublisherForV11Naming() =>
EndpointSetup<DefaultServer>(b =>
{
b.Tracing().UseMessageTypeNamesInSpanNames = true;
b.OnEndpointSubscribed<Context>((s, context) =>
{
if (s.SubscriberEndpoint.Contains(Conventions.EndpointNamingConvention(typeof(SubscriberForPublisherWithDestinationNaming))))
if (s.SubscriberEndpoint.Contains(Conventions.EndpointNamingConvention(typeof(SubscriberForPublisherForV11Naming))))
{
if (s.MessageType == typeof(ThisIsAnEvent).AssemblyQualifiedName)
{
Expand All @@ -222,13 +222,13 @@ public PublisherWithDestinationNaming() =>
});
}

public class SubscriberForPublisherWithDestinationNaming : EndpointConfigurationBuilder
public class SubscriberForPublisherForV11Naming : EndpointConfigurationBuilder
{
public SubscriberForPublisherWithDestinationNaming() =>
public SubscriberForPublisherForV11Naming() =>
EndpointSetup<DefaultServer>(c => { },
metadata =>
{
metadata.RegisterPublisherFor<ThisIsAnEvent, PublisherWithDestinationNaming>();
metadata.RegisterPublisherFor<ThisIsAnEvent, PublisherForV11Naming>();
});

[Handler]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,12 @@ await Scenario.Define<Context>()
}

[Test]
public async Task Should_include_destination_in_display_name_when_opted_in()
[OpenTelemetryV11Defaults]
public async Task Should_include_destination_in_display_name()
{
await Scenario.Define<Context>()
.WithEndpoint<RecoverabilityEndpoint>(b => b
.CustomConfig(c =>
{
c.Recoverability().Immediate(i => i.NumberOfRetries(1)).Delayed(i => i.NumberOfRetries(0));
c.Tracing().UseMessageTypeNamesInSpanNames = true;
})
.CustomConfig(c => c.Recoverability().Immediate(i => i.NumberOfRetries(1)).Delayed(i => i.NumberOfRetries(0)))
.DoNotFailOnErrorMessages()
.When(s => s.SendLocal(new FailingMessage())))
.Done(_ => ActionTags().Contains("move_to_error"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,11 @@ public Task Handle(OutgoingMessage message, IMessageHandlerContext context)
}

[Test]
public async Task Should_use_destination_in_send_span_name_when_opted_in()
[OpenTelemetryV11Defaults]
public async Task Should_include_destination_in_send_span_name()
{
await Scenario.Define<Context>()
.WithEndpoint<TestEndpointWithDestinationNaming>(b => b
.WithEndpoint<TestEndpoint>(b => b
.When(s => s.SendLocal(new OutgoingMessage())))
.Run();

Expand All @@ -147,22 +148,6 @@ await Scenario.Define<Context>()
Assert.That(sentMessage.DisplayName, Is.Not.EqualTo("send message"));
}

public class TestEndpointWithDestinationNaming : EndpointConfigurationBuilder
{
public TestEndpointWithDestinationNaming() =>
EndpointSetup<DefaultServer>(b => b.Tracing().UseMessageTypeNamesInSpanNames = true);

[Handler]
public class MessageHandler(Context testContext) : IHandleMessages<OutgoingMessage>
{
public Task Handle(OutgoingMessage message, IMessageHandlerContext context)
{
testContext.MarkAsCompleted();
return Task.CompletedTask;
}
}
}

[Test]
public async Task Should_create_new_linked_trace_on_receive_when_endpoint_defaults_to_span_link()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@ public Task Handle(OutgoingReply message, IMessageHandlerContext context)
}

[Test]
public async Task Should_use_destination_in_reply_span_name_when_opted_in()
[OpenTelemetryV11Defaults]
public async Task Should_include_destination_in_reply_span_name()
{
await Scenario.Define<Context>()
.WithEndpoint<TestEndpointWithDestinationNaming>(b => b
.WithEndpoint<TestEndpoint>(b => b
.When(s => s.SendLocal(new IncomingMessage())))
.Run();

Expand All @@ -70,25 +71,6 @@ await Scenario.Define<Context>()
Assert.That(replyMessage.DisplayName, Does.StartWith("reply "));
}

public class TestEndpointWithDestinationNaming : EndpointConfigurationBuilder
{
public TestEndpointWithDestinationNaming() =>
EndpointSetup<DefaultServer>(b => b.Tracing().UseMessageTypeNamesInSpanNames = true);

[Handler]
public class MessageHandler(Context testContext) : IHandleMessages<IncomingMessage>,
IHandleMessages<OutgoingReply>
{
public Task Handle(IncomingMessage message, IMessageHandlerContext context) => context.Reply(new OutgoingReply());

public Task Handle(OutgoingReply message, IMessageHandlerContext context)
{
testContext.MarkAsCompleted();
return Task.CompletedTask;
}
}
}

public class IncomingMessage : IMessage;

public class OutgoingReply : IMessage;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
<RemoveSourceFileFromPackage Include="Core\**\*.cs" />
<RemoveSourceFileFromPackage Include="AssemblyInfo.cs" />
<RemoveSourceFileFromPackage Include="AcceptanceTestsShippedSourceFilesApproval.cs" />
<RemoveSourceFileFromPackage Include="obsoletes-v10.cs" />
<RemoveSourceFileFromPackage Include="Registrations\Handlers\When_multiple_namespaces.cs" />
<RemoveSourceFileFromPackage Include="Registrations\Handlers\When_registering_handler_with_complex_hierarchy.cs" />
</ItemGroup>
Expand Down
40 changes: 40 additions & 0 deletions src/NServiceBus.AcceptanceTests/obsoletes-v10.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
namespace NServiceBus.AcceptanceTests;

using System;
using System.Reflection;
using NUnit.Framework;
using NUnit.Framework.Interfaces;

// =============================================================================
// EVERYTHING IN THIS FILE IS TEMPORARY AND WILL BE REMOVED IN v11, together with
// the V11BehaviorSwitch block in NServiceBus.Core/obsoletes-v10.cs. The file is
// excluded from the shipped acceptance test sources in the project file.
// =============================================================================

// Runs the test with the NServiceBus.Core.OpenTelemetry.UseV11Behavior AppContext switch enabled, i.e. with
// the OpenTelemetry defaults of v11. The switch value is cached process-wide, so the cache is reset through
// the internal V11BehaviorSwitch.ResetUseV11Behavior method. Only safe in [NonParallelizable] fixtures such
// as OpenTelemetryAcceptanceTest. In v11 these defaults are the only behavior: delete this attribute and
// remove it from the tests that use it.
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
public sealed class OpenTelemetryV11DefaultsAttribute : Attribute, ITestAction
{
const string SwitchName = "NServiceBus.Core.OpenTelemetry.UseV11Behavior";

static readonly MethodInfo ResetSwitch = typeof(EndpointConfiguration).Assembly
.GetType("NServiceBus.V11BehaviorSwitch", throwOnError: true)!
.GetMethod("ResetUseV11Behavior", BindingFlags.Static | BindingFlags.NonPublic)
?? throw new InvalidOperationException("NServiceBus.V11BehaviorSwitch.ResetUseV11Behavior not found");

public ActionTargets Targets => ActionTargets.Test;

public void BeforeTest(ITest test) => Set(true);

public void AfterTest(ITest test) => Set(false);

static void Set(bool enabled)
{
AppContext.SetSwitch(SwitchName, enabled);
ResetSwitch.Invoke(null, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -691,13 +691,10 @@ namespace NServiceBus
{
public InstrumentationOptions() { }
public NServiceBus.DelayedDeliveryInstrumentationOptions DelayedDelivery { get; }
public bool EmitMessageDispatchingEvents { get; set; }
public NServiceBus.ExceptionRecordingMode ExceptionRecordingMode { get; set; }
public NServiceBus.MetersOptions Meters { get; }
public NServiceBus.TraceMode PublishTraceMode { get; set; }
public NServiceBus.RecoverabilityInstrumentationOptions Recoverability { get; }
public NServiceBus.TraceMode SendTraceMode { get; set; }
public bool UseMessageTypeNamesInSpanNames { get; set; }
}
public sealed class KeyedServiceKey
{
Expand Down Expand Up @@ -857,11 +854,6 @@ namespace NServiceBus
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(@"AddMessageType<TMessage> relies on an NServiceBus source-generated interceptor to register the statically known message hierarchy without reflection when trimming is enabled. If this warning is reported, the interceptor was not used for this call; enable or restore the NServiceBus analyzer/source-generator tooling and use a statically known message type.")]
public static void AddMessageType<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.None | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.Interfaces)] TMessage>(this NServiceBus.EndpointConfiguration config) { }
}
public class MetersOptions
{
public MetersOptions() { }
public bool EmitExecutionResultTags { get; set; }
}
public static class MetricTagsExtensions
{
extension(NServiceBus.Pipeline.IBehaviorContext context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public void Setup()
originalBody = "payload"u8.ToArray().AsMemory();
messageContext = new MessageContext(nativeId, originalHeaders, originalBody, new TransportTransaction(), "receiveAddress", new ContextBag());
meterFactory = new TestMeterFactory();
pipelineMetrics = new PipelineMetrics(meterFactory, "queue", "disc", new MetersOptions());
pipelineMetrics = new PipelineMetrics(meterFactory, "queue", "disc");
}

[TearDown]
Expand Down
23 changes: 5 additions & 18 deletions src/NServiceBus.Core.Tests/OpenTelemetry/ActivityFactoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,26 +49,13 @@ static MessageContext CreateMessageContext() =>
new(Guid.NewGuid().ToString(), [], Array.Empty<byte>(), new TransportTransaction(), "receiver", new ContextBag());
}

// Until v11 the "transport span as parent" behavior is opt-in. This fixture runs with the v11
// defaults because that is what the tests below describe; the pre-v11 default is covered by
// TransportParentSpanDefaultBehaviorTests. In v11, remove the attribute together with the
// V11BehaviorSwitch block in obsoletes-v10.cs.
[OpenTelemetryV11Defaults]
class StartIncomingActivity : ActivityFactoryTests
{
// Until v11 the "transport span as parent" behavior is opt-in. This fixture runs with it
// enabled because that is the v11 default the tests below describe; the pre-v11 default
// is covered by TransportParentSpanDefaultBehaviorTests. In v11, delete this SetUp/TearDown
// pair together with obsolete_v11.cs.
[SetUp]
public void OptInToTransportSpanAsParent()
{
AppContext.SetSwitch(TransportParentActivitySwitch.UseTransportActivityAsParentSwitchName, true);
TransportParentActivitySwitch.ResetUseTransportActivityAsParent();
}

[TearDown]
public void ResetTransportSpanSwitch()
{
AppContext.SetSwitch(TransportParentActivitySwitch.UseTransportActivityAsParentSwitchName, false);
TransportParentActivitySwitch.ResetUseTransportActivityAsParent();
}

[TestCase(Headers.NServiceBusDiagnosticsTraceParent)]
[TestCase(Headers.DiagnosticsTraceParent)] // for backwards compatibility
public void Should_attach_to_header_trace_when_available_and_no_ambient_activity(string headerName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,9 @@
using NUnit.Framework;

[TestFixture]
[OpenTelemetryV11Defaults]
public class ContextPropagationCompatibilityTests
{
[SetUp]
public void EnableDistributedContextPropagator()
{
AppContext.SetSwitch(LegacyContextPropagation.UseDistributedContextPropagatorSwitchName, true);
LegacyContextPropagation.ResetUseDistributedContextPropagator();
}

[TearDown]
public void ResetDistributedContextPropagator()
{
AppContext.SetSwitch(LegacyContextPropagation.UseDistributedContextPropagatorSwitchName, false);
LegacyContextPropagation.ResetUseDistributedContextPropagator();
}

delegate void Writer(Activity activity, Dictionary<string, string> headers);

delegate void Reader(Activity activity, IDictionary<string, string> headers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,8 @@
[TestFixture]
public class ContextPropagationDefaultBehaviorTests
{
// Without the opt-in switch, the endpoint default must remain the backwards-compatible
// legacy propagator (percent-encoded, comma-separated, whitespace preserved).
[SetUp]
public void EnsureDefault()
{
AppContext.SetSwitch(LegacyContextPropagation.UseDistributedContextPropagatorSwitchName, false);
LegacyContextPropagation.ResetUseDistributedContextPropagator();
}

// Without the OpenTelemetryV11Defaults attribute, the endpoint default must remain the
// backwards-compatible legacy propagator (percent-encoded, comma-separated, whitespace preserved).
[Test]
public void Default_uses_legacy_percent_encoded_baggage_format()
{
Expand Down
Loading
Loading