From 8c8c1b5cdb1a9e4aa8b39d3f83e39702616ef03d Mon Sep 17 00:00:00 2001 From: Jimmy Bogard Date: Wed, 9 Feb 2022 20:57:55 -0600 Subject: [PATCH 1/2] Placing activity in a context object for easier access; fixes #11 --- README.md | 15 ++++++++++ .../CurrentContextActivity.cs | 17 +++++++++++ .../ICurrentActivity.cs | 8 +++++ .../IncomingPhysicalMessageDiagnostics.cs | 20 +++++++++---- .../NServiceBus.Extensions.Diagnostics.csproj | 12 ++++++-- .../OutgoingLogicalMessageDiagnostics.cs | 20 +++++++++---- .../OutgoingPhysicalMessageDiagnostics.cs | 5 +++- ...IncomingPhysicalMessageDiagnosticsTests.cs | 30 +++++++++++++++++++ ...iceBus.Extensions.Diagnostics.Tests.csproj | 12 ++++---- .../OutgoingLogicalMessageDiagnosticsTests.cs | 30 +++++++++++++++++++ ...OutgoingPhysicalMessageDiagnosticsTests.cs | 22 +++++++++++++- 11 files changed, 170 insertions(+), 21 deletions(-) create mode 100644 src/NServiceBus.Extensions.Diagnostics/CurrentContextActivity.cs create mode 100644 src/NServiceBus.Extensions.Diagnostics/ICurrentActivity.cs diff --git a/README.md b/README.md index e126aa8..a1fd95a 100644 --- a/README.md +++ b/README.md @@ -64,3 +64,18 @@ settings.Set(new NServiceBus.Extensions.Diagnostics.InstrumentationOptions ``` This will set a `messaging.message_payload` tag with the UTF8-decoded message body. + +### Enriching Activities + +To enrich an Activity in a behavior or handler, the current executing NServiceBus activity is set in a `ICurrentActivity` extension value. In a handler or behavior you may retrieve this value and modify the `Activity`: + +```csharp +public Task Handle(Message message, IMessageHandlerContext context) +{ + var currentActivity = context.Extensions.Get(); + + currentActivity.Current?.AddBaggage("cart.operation.id", message.Id.ToString()); + + // rest of method +} +``` \ No newline at end of file diff --git a/src/NServiceBus.Extensions.Diagnostics/CurrentContextActivity.cs b/src/NServiceBus.Extensions.Diagnostics/CurrentContextActivity.cs new file mode 100644 index 0000000..8ccfa7f --- /dev/null +++ b/src/NServiceBus.Extensions.Diagnostics/CurrentContextActivity.cs @@ -0,0 +1,17 @@ +using System; +using System.Diagnostics; + +namespace NServiceBus.Extensions.Diagnostics; + +class CurrentContextActivity : ICurrentActivity, IDisposable +{ + public CurrentContextActivity(Activity? current) => Current = current; + + public Activity? Current { get; private set; } + + public void Dispose() + { + Current?.Dispose(); + Current = null; + } +} \ No newline at end of file diff --git a/src/NServiceBus.Extensions.Diagnostics/ICurrentActivity.cs b/src/NServiceBus.Extensions.Diagnostics/ICurrentActivity.cs new file mode 100644 index 0000000..b06b807 --- /dev/null +++ b/src/NServiceBus.Extensions.Diagnostics/ICurrentActivity.cs @@ -0,0 +1,8 @@ +using System.Diagnostics; + +namespace NServiceBus.Extensions.Diagnostics; + +public interface ICurrentActivity +{ + public Activity? Current { get; } +} \ No newline at end of file diff --git a/src/NServiceBus.Extensions.Diagnostics/IncomingPhysicalMessageDiagnostics.cs b/src/NServiceBus.Extensions.Diagnostics/IncomingPhysicalMessageDiagnostics.cs index e0d448c..d0b9903 100644 --- a/src/NServiceBus.Extensions.Diagnostics/IncomingPhysicalMessageDiagnostics.cs +++ b/src/NServiceBus.Extensions.Diagnostics/IncomingPhysicalMessageDiagnostics.cs @@ -24,14 +24,24 @@ public override async Task Invoke( IIncomingPhysicalMessageContext context, Func next) { - using (StartActivity(context)) + using var activity = StartActivity(context); + + using var currentContextActivity = new CurrentContextActivity(activity); + + try { + context.Extensions.Set(currentContextActivity); + await next().ConfigureAwait(false); + } + finally + { + context.Extensions.Remove(); + } - if (_diagnosticListener.IsEnabled(EventName)) - { - _diagnosticListener.Write(EventName, context); - } + if (_diagnosticListener.IsEnabled(EventName)) + { + _diagnosticListener.Write(EventName, context); } } diff --git a/src/NServiceBus.Extensions.Diagnostics/NServiceBus.Extensions.Diagnostics.csproj b/src/NServiceBus.Extensions.Diagnostics/NServiceBus.Extensions.Diagnostics.csproj index ab43bf4..f3a74d2 100644 --- a/src/NServiceBus.Extensions.Diagnostics/NServiceBus.Extensions.Diagnostics.csproj +++ b/src/NServiceBus.Extensions.Diagnostics/NServiceBus.Extensions.Diagnostics.csproj @@ -21,10 +21,16 @@ - - + + - + + + + + + <_Parameter1>NServiceBus.Extensions.Diagnostics.Tests + diff --git a/src/NServiceBus.Extensions.Diagnostics/OutgoingLogicalMessageDiagnostics.cs b/src/NServiceBus.Extensions.Diagnostics/OutgoingLogicalMessageDiagnostics.cs index 3587525..e7e79ef 100644 --- a/src/NServiceBus.Extensions.Diagnostics/OutgoingLogicalMessageDiagnostics.cs +++ b/src/NServiceBus.Extensions.Diagnostics/OutgoingLogicalMessageDiagnostics.cs @@ -18,14 +18,24 @@ public OutgoingLogicalMessageDiagnostics() public override async Task Invoke(IOutgoingLogicalMessageContext context, Func next) { - using (StartActivity()) + using var activity = StartActivity(); + + using var currentContextActivity = new CurrentContextActivity(activity); + + try { + context.Extensions.Set(currentContextActivity); + await next().ConfigureAwait(false); + } + finally + { + context.Extensions.Remove(); + } - if (_diagnosticListener.IsEnabled(EventName)) - { - _diagnosticListener.Write(EventName, context); - } + if (_diagnosticListener.IsEnabled(EventName)) + { + _diagnosticListener.Write(EventName, context); } } diff --git a/src/NServiceBus.Extensions.Diagnostics/OutgoingPhysicalMessageDiagnostics.cs b/src/NServiceBus.Extensions.Diagnostics/OutgoingPhysicalMessageDiagnostics.cs index c7fb615..cc30398 100644 --- a/src/NServiceBus.Extensions.Diagnostics/OutgoingPhysicalMessageDiagnostics.cs +++ b/src/NServiceBus.Extensions.Diagnostics/OutgoingPhysicalMessageDiagnostics.cs @@ -26,7 +26,10 @@ public OutgoingPhysicalMessageDiagnostics(DiagnosticListener diagnosticListener, public override async Task Invoke(IOutgoingPhysicalMessageContext context, Func next) { - var activity = Activity.Current; + var activity = context.Extensions.TryGet(out var currentActivity) + ? currentActivity.Current + : Activity.Current; + if (activity != null) { _activityEnricher.Enrich(activity, context); diff --git a/test/NServiceBus.Extensions.Diagnostics.Tests/IncomingPhysicalMessageDiagnosticsTests.cs b/test/NServiceBus.Extensions.Diagnostics.Tests/IncomingPhysicalMessageDiagnosticsTests.cs index 6bf738f..10c6d6b 100644 --- a/test/NServiceBus.Extensions.Diagnostics.Tests/IncomingPhysicalMessageDiagnosticsTests.cs +++ b/test/NServiceBus.Extensions.Diagnostics.Tests/IncomingPhysicalMessageDiagnosticsTests.cs @@ -62,6 +62,36 @@ public async Task Should_fire_activity_start_stop_when_listener_attached() stopFired.ShouldBeTrue(); } + [Fact] + public async Task Should_set_current_activity_in_context() + { + var context = new TestableIncomingPhysicalMessageContext(); + + using var listener = new ActivityListener + { + ShouldListenTo = source => source.Name == "NServiceBus.Extensions.Diagnostics", + Sample = (ref ActivityCreationOptions _) => ActivitySamplingResult.AllDataAndRecorded, + }; + ActivitySource.AddActivityListener(listener); + + var behavior = new IncomingPhysicalMessageDiagnostics(new FakeActivityEnricher()); + + var found = false; + var hasActivity = false; + + await behavior.Invoke(context, () => + { + found = context.Extensions.TryGet(out var currentActivity); + hasActivity = currentActivity?.Current != null; + + return Task.CompletedTask; + }); + + found.ShouldBeTrue(); + hasActivity.ShouldBeTrue(); + context.Extensions.TryGet(out _).ShouldBeFalse(); + } + [Fact] public async Task Should_start_and_log_activity() { diff --git a/test/NServiceBus.Extensions.Diagnostics.Tests/NServiceBus.Extensions.Diagnostics.Tests.csproj b/test/NServiceBus.Extensions.Diagnostics.Tests/NServiceBus.Extensions.Diagnostics.Tests.csproj index 7d6d622..6ccddc7 100644 --- a/test/NServiceBus.Extensions.Diagnostics.Tests/NServiceBus.Extensions.Diagnostics.Tests.csproj +++ b/test/NServiceBus.Extensions.Diagnostics.Tests/NServiceBus.Extensions.Diagnostics.Tests.csproj @@ -7,16 +7,16 @@ - - - - + + + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/NServiceBus.Extensions.Diagnostics.Tests/OutgoingLogicalMessageDiagnosticsTests.cs b/test/NServiceBus.Extensions.Diagnostics.Tests/OutgoingLogicalMessageDiagnosticsTests.cs index 50b80e3..41f7548 100644 --- a/test/NServiceBus.Extensions.Diagnostics.Tests/OutgoingLogicalMessageDiagnosticsTests.cs +++ b/test/NServiceBus.Extensions.Diagnostics.Tests/OutgoingLogicalMessageDiagnosticsTests.cs @@ -55,6 +55,36 @@ public async Task Should_fire_activity_start_stop_when_listener_attached() stopFired.ShouldBeTrue(); } + [Fact] + public async Task Should_set_current_activity_in_context() + { + var context = new TestableOutgoingLogicalMessageContext(); + + using var listener = new ActivityListener + { + ShouldListenTo = source => source.Name == "NServiceBus.Extensions.Diagnostics", + Sample = (ref ActivityCreationOptions _) => ActivitySamplingResult.AllDataAndRecorded, + }; + ActivitySource.AddActivityListener(listener); + + var behavior = new OutgoingLogicalMessageDiagnostics(); + + var found = false; + var hasActivity = false; + + await behavior.Invoke(context, () => + { + found = context.Extensions.TryGet(out var currentActivity); + hasActivity = currentActivity?.Current != null; + + return Task.CompletedTask; + }); + + found.ShouldBeTrue(); + hasActivity.ShouldBeTrue(); + context.Extensions.TryGet(out _).ShouldBeFalse(); + } + [Fact] public async Task Should_start_and_log_activity() { diff --git a/test/NServiceBus.Extensions.Diagnostics.Tests/OutgoingPhysicalMessageDiagnosticsTests.cs b/test/NServiceBus.Extensions.Diagnostics.Tests/OutgoingPhysicalMessageDiagnosticsTests.cs index d39c1dd..eaae486 100644 --- a/test/NServiceBus.Extensions.Diagnostics.Tests/OutgoingPhysicalMessageDiagnosticsTests.cs +++ b/test/NServiceBus.Extensions.Diagnostics.Tests/OutgoingPhysicalMessageDiagnosticsTests.cs @@ -61,7 +61,7 @@ public async Task Should_fire_activity_start_stop_when_listener_attached() } [Fact] - public async Task Should_set_appropriate_headers() + public async Task Should_set_appropriate_headers_from_current_activity() { var context = new TestableOutgoingPhysicalMessageContext(); @@ -84,5 +84,25 @@ public async Task Should_set_appropriate_headers() context.Headers.ShouldContain(kvp => kvp.Key == "Correlation-Context" && kvp.Value == "Key2=Value2,Key1=Value1"); context.Headers.ShouldContain(kvp => kvp.Key == "baggage" && kvp.Value == "Key2=Value2,Key1=Value1"); } + + [Fact] + public async Task Should_set_appropriate_headers() + { + var context = new TestableOutgoingPhysicalMessageContext(); + + var behavior = new OutgoingPhysicalMessageDiagnostics(new FakeActivityEnricher()); + + using var outerActivity = new Activity("Outer"); + outerActivity.AddBaggage("Key1", "Value1"); + outerActivity.AddBaggage("Key2", "Value2"); + + using var currentActivity = new CurrentContextActivity(outerActivity); + context.Extensions.Set(currentActivity); + + await behavior.Invoke(context, () => Task.CompletedTask); + + context.Headers.ShouldContain(kvp => kvp.Key == "Correlation-Context" && kvp.Value == "Key2=Value2,Key1=Value1"); + context.Headers.ShouldContain(kvp => kvp.Key == "baggage" && kvp.Value == "Key2=Value2,Key1=Value1"); + } } } From aae693b224cff95c1b887ae23eee83a1dc11f7c2 Mon Sep 17 00:00:00 2001 From: Jimmy Bogard Date: Wed, 9 Feb 2022 20:59:41 -0600 Subject: [PATCH 2/2] Updating to .NET 6 --- .github/workflows/ci.yml | 8 ++------ .github/workflows/release.yml | 8 ++------ .../NServiceBus.Extensions.Diagnostics.Tests.csproj | 2 +- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 333db84..6403535 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,14 +15,10 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 0 - - name: Setup dotnet 5.0 + - name: Setup dotnet 6.0 uses: actions/setup-dotnet@v1 with: - dotnet-version: '5.0.100' - - name: Setup dotnet 3.1 - uses: actions/setup-dotnet@v1 - with: - dotnet-version: '3.1.x' + dotnet-version: '6.0.101' - name: Build and Test run: ./Build.ps1 shell: pwsh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1955e05..fc487fa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,14 +12,10 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 0 - - name: Setup dotnet 5.0 + - name: Setup dotnet 6.0 uses: actions/setup-dotnet@v1 with: - dotnet-version: '5.0.100' - - name: Setup dotnet 3.1 - uses: actions/setup-dotnet@v1 - with: - dotnet-version: '3.1.x' + dotnet-version: '6.0.101' - name: Build and Test run: ./Build.ps1 shell: pwsh diff --git a/test/NServiceBus.Extensions.Diagnostics.Tests/NServiceBus.Extensions.Diagnostics.Tests.csproj b/test/NServiceBus.Extensions.Diagnostics.Tests/NServiceBus.Extensions.Diagnostics.Tests.csproj index 6ccddc7..368a868 100644 --- a/test/NServiceBus.Extensions.Diagnostics.Tests/NServiceBus.Extensions.Diagnostics.Tests.csproj +++ b/test/NServiceBus.Extensions.Diagnostics.Tests/NServiceBus.Extensions.Diagnostics.Tests.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1 + net6.0 false