diff --git a/.github/workflows/all_solutions.yml b/.github/workflows/all_solutions.yml
index 481015bb8d..f8e744a46a 100644
--- a/.github/workflows/all_solutions.yml
+++ b/.github/workflows/all_solutions.yml
@@ -423,6 +423,7 @@ jobs:
matrix:
namespace:
[
+ AzureServiceBus,
CosmosDB,
Couchbase,
Elasticsearch,
diff --git a/FullAgent.sln b/FullAgent.sln
index 113ac8211a..e54f549c3a 100644
--- a/FullAgent.sln
+++ b/FullAgent.sln
@@ -152,10 +152,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Home", "src\Agent\NewRelic\
{338AD83A-ED68-438A-8FB1-E93A3AE87EA8} = {338AD83A-ED68-438A-8FB1-E93A3AE87EA8}
{37262C22-6A3A-4AD7-AB78-3853D2B2931D} = {37262C22-6A3A-4AD7-AB78-3853D2B2931D}
{3D69B4C9-FD16-461F-95AF-6FCA6EAA914E} = {3D69B4C9-FD16-461F-95AF-6FCA6EAA914E}
+ {4078E594-E738-48F7-A7ED-B208ADD04900} = {4078E594-E738-48F7-A7ED-B208ADD04900}
{44434B8F-EE14-49B0-855D-6EA0B48048BF} = {44434B8F-EE14-49B0-855D-6EA0B48048BF}
{4F5D77F3-B41A-44A7-AF10-2D5462CE0162} = {4F5D77F3-B41A-44A7-AF10-2D5462CE0162}
{570429FD-C785-4673-82DF-643D06B6DC53} = {570429FD-C785-4673-82DF-643D06B6DC53}
{5BBEEC11-B753-4631-BCDD-43BE73B5CCAC} = {5BBEEC11-B753-4631-BCDD-43BE73B5CCAC}
+ {5D74E5C5-9BA3-423B-86F7-14C2D1A14661} = {5D74E5C5-9BA3-423B-86F7-14C2D1A14661}
{614988AD-7C73-4E71-8F95-520D5F485984} = {614988AD-7C73-4E71-8F95-520D5F485984}
{64C7F267-5185-4AB7-9EB5-0183D8BB0171} = {64C7F267-5185-4AB7-9EB5-0183D8BB0171}
{686AE051-BC8C-4AEC-803D-237AEB807CA9} = {686AE051-BC8C-4AEC-803D-237AEB807CA9}
@@ -221,6 +223,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PublicApiChangeTests", "tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Memcached", "src\Agent\NewRelic\Agent\Extensions\Providers\Wrapper\Memcached\Memcached.csproj", "{5D74E5C5-9BA3-423B-86F7-14C2D1A14661}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureServiceBus", "src\Agent\NewRelic\Agent\Extensions\Providers\Wrapper\AzureServiceBus\AzureServiceBus.csproj", "{4078E594-E738-48F7-A7ED-B208ADD04900}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -467,6 +471,10 @@ Global
{5D74E5C5-9BA3-423B-86F7-14C2D1A14661}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5D74E5C5-9BA3-423B-86F7-14C2D1A14661}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5D74E5C5-9BA3-423B-86F7-14C2D1A14661}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4078E594-E738-48F7-A7ED-B208ADD04900}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4078E594-E738-48F7-A7ED-B208ADD04900}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4078E594-E738-48F7-A7ED-B208ADD04900}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4078E594-E738-48F7-A7ED-B208ADD04900}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -538,6 +546,7 @@ Global
{338AD83A-ED68-438A-8FB1-E93A3AE87EA8} = {5E86E10A-C38F-48CB-ADE9-67B22BB2F50A}
{A8F6EFEA-1C31-4461-A7B4-25C30D954EE2} = {E5B988C0-5D19-407E-8210-71FFB90C579A}
{5D74E5C5-9BA3-423B-86F7-14C2D1A14661} = {5E86E10A-C38F-48CB-ADE9-67B22BB2F50A}
+ {4078E594-E738-48F7-A7ED-B208ADD04900} = {5E86E10A-C38F-48CB-ADE9-67B22BB2F50A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D8B98070-6B8E-403C-A07F-A3F2E4A3A3D0}
diff --git a/build/ArtifactBuilder/CoreAgentComponents.cs b/build/ArtifactBuilder/CoreAgentComponents.cs
index 94bbafde91..6067173c07 100644
--- a/build/ArtifactBuilder/CoreAgentComponents.cs
+++ b/build/ArtifactBuilder/CoreAgentComponents.cs
@@ -60,6 +60,7 @@ protected override void CreateAgentComponents()
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AwsSdk.dll",
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AzureFunction.dll",
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Memcached.dll",
+ $@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AzureServiceBus.dll",
};
var wrapperXmls = new[]
@@ -88,6 +89,7 @@ protected override void CreateAgentComponents()
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AwsSdk.Instrumentation.xml",
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AzureFunction.Instrumentation.xml",
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Memcached.Instrumentation.xml",
+ $@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AzureServiceBus.Instrumentation.xml",
};
ExtensionXsd = $@"{SourceHomeBuilderPath}\extensions\extension.xsd";
diff --git a/build/ArtifactBuilder/FrameworkAgentComponents.cs b/build/ArtifactBuilder/FrameworkAgentComponents.cs
index 7f6bd9666a..f50969353c 100644
--- a/build/ArtifactBuilder/FrameworkAgentComponents.cs
+++ b/build/ArtifactBuilder/FrameworkAgentComponents.cs
@@ -67,6 +67,7 @@ protected override void CreateAgentComponents()
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AwsSdk.dll",
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AzureFunction.dll",
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Memcached.dll",
+ $@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AzureServiceBus.dll",
};
var wrapperXmls = new[]
@@ -109,6 +110,7 @@ protected override void CreateAgentComponents()
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AwsSdk.Instrumentation.xml",
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AzureFunction.Instrumentation.xml",
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Memcached.Instrumentation.xml",
+ $@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AzureServiceBus.Instrumentation.xml",
};
ExtensionXsd = $@"{SourceHomeBuilderPath}\extensions\extension.xsd";
diff --git a/src/Agent/MsiInstaller/Installer/Product.wxs b/src/Agent/MsiInstaller/Installer/Product.wxs
index 83adb71f46..c61a5f6c77 100644
--- a/src/Agent/MsiInstaller/Installer/Product.wxs
+++ b/src/Agent/MsiInstaller/Installer/Product.wxs
@@ -404,6 +404,9 @@ SPDX-License-Identifier: Apache-2.0
+
+
+
@@ -481,6 +484,9 @@ SPDX-License-Identifier: Apache-2.0
+
+
+
@@ -600,6 +606,9 @@ SPDX-License-Identifier: Apache-2.0
+
+
+
@@ -675,6 +684,9 @@ SPDX-License-Identifier: Apache-2.0
+
+
+
diff --git a/src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/Api/ITransaction.cs b/src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/Api/ITransaction.cs
index c8fd50cfaf..6bcf07aebc 100644
--- a/src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/Api/ITransaction.cs
+++ b/src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/Api/ITransaction.cs
@@ -92,6 +92,9 @@ public interface ITransaction
///
///
///
+ ///
+ ///
+ ///
///
/// an opaque object that will be needed when you want to end the segment.
ISegment StartMessageBrokerSegment(MethodCall methodCall, MessageBrokerDestinationType destinationType,
diff --git a/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AzureServiceBus/AzureServiceBus.csproj b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AzureServiceBus/AzureServiceBus.csproj
new file mode 100644
index 0000000000..9e5be87e32
--- /dev/null
+++ b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AzureServiceBus/AzureServiceBus.csproj
@@ -0,0 +1,22 @@
+
+
+ net462;netstandard2.0
+ NewRelic.Providers.Wrapper.AzureServiceBus
+ NewRelic.Providers.Wrapper.AzureServiceBus
+ Azure Service Bus Wrapper Provider for New Relic .NET Agent
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AzureServiceBus/AzureServiceBusReceiveWrapper.cs b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AzureServiceBus/AzureServiceBusReceiveWrapper.cs
new file mode 100644
index 0000000000..01e58c33f8
--- /dev/null
+++ b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AzureServiceBus/AzureServiceBusReceiveWrapper.cs
@@ -0,0 +1,143 @@
+// Copyright 2020 New Relic, Inc. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Threading.Tasks;
+using NewRelic.Agent.Api;
+using NewRelic.Agent.Extensions.Providers.Wrapper;
+using NewRelic.Reflection;
+
+namespace NewRelic.Providers.Wrapper.AzureServiceBus;
+
+public class AzureServiceBusReceiveWrapper : AzureServiceBusWrapperBase
+{
+ private static readonly ConcurrentDictionary> _getResultFromGenericTask = new();
+
+ public override CanWrapResponse CanWrap(InstrumentedMethodInfo instrumentedMethodInfo)
+ {
+ var canWrap = instrumentedMethodInfo.RequestedWrapperName.Equals(nameof(AzureServiceBusReceiveWrapper));
+ return new CanWrapResponse(canWrap);
+ }
+
+ public override AfterWrappedMethodDelegate BeforeWrappedMethod(InstrumentedMethodCall instrumentedMethodCall, IAgent agent, ITransaction transaction)
+ {
+ dynamic serviceBusReceiver = instrumentedMethodCall.MethodCall.InvocationTarget;
+ string queueName = serviceBusReceiver.EntityPath; // some-queue-name
+ string fqns = serviceBusReceiver.FullyQualifiedNamespace; // some-service-bus-entity.servicebus.windows.net
+
+ MessageBrokerAction action =
+ instrumentedMethodCall.MethodCall.Method.MethodName switch
+ {
+ "ReceiveMessagesAsync" => MessageBrokerAction.Consume,
+ "ReceiveDeferredMessagesAsync" => MessageBrokerAction.Consume,
+ "PeekMessagesInternalAsync" => MessageBrokerAction.Peek,
+ "AbandonMessageAsync" => MessageBrokerAction.Purge, // TODO is this correct ??? Abandon sends the message back to the queue for re-delivery
+ "CompleteMessageAsync" => MessageBrokerAction.Consume,
+ "DeadLetterInternalAsync" => MessageBrokerAction.Purge, // TODO is this correct ???
+ "DeferMessageAsync" => MessageBrokerAction.Consume, // TODO is this correct or should we extend MessageBrokerAction with more values???
+ "RenewMessageLockAsync" => MessageBrokerAction.Consume, // TODO is this correct or should we extend MessageBrokerAction with more values???
+ _ => throw new ArgumentOutOfRangeException(nameof(action), $"Unexpected instrumented method call: {instrumentedMethodCall.MethodCall.Method.MethodName}")
+ };
+
+ // start a message broker segment
+ var segment = transaction.StartMessageBrokerSegment(
+ instrumentedMethodCall.MethodCall,
+ MessageBrokerDestinationType.Queue,
+ action,
+ BrokerVendorName,
+ queueName,
+ serverAddress: fqns );
+
+ return instrumentedMethodCall.IsAsync
+ ?
+ // return an async delegate
+ Delegates.GetAsyncDelegateFor(
+ agent,
+ segment,
+ false,
+ HandleResponse,
+ TaskContinuationOptions.ExecuteSynchronously)
+ : Delegates.GetDelegateFor