diff --git a/FullAgent.sln b/FullAgent.sln index 404120280..8f72b5e2e 100644 --- a/FullAgent.sln +++ b/FullAgent.sln @@ -157,6 +157,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Home", "src\Agent\NewRelic\ {279F8AD0-C959-476F-BD58-3581D9A33238} = {279F8AD0-C959-476F-BD58-3581D9A33238} {2E6CF650-CB50-453D-830A-D00F0540FC2C} = {2E6CF650-CB50-453D-830A-D00F0540FC2C} {2FB30555-65A4-43D7-82AA-56BF203D3A96} = {2FB30555-65A4-43D7-82AA-56BF203D3A96} + {37262C22-6A3A-4AD7-AB78-3853D2B2931D} = {37262C22-6A3A-4AD7-AB78-3853D2B2931D} {3D69B4C9-FD16-461F-95AF-6FCA6EAA914E} = {3D69B4C9-FD16-461F-95AF-6FCA6EAA914E} {44434B8F-EE14-49B0-855D-6EA0B48048BF} = {44434B8F-EE14-49B0-855D-6EA0B48048BF} {4F5D77F3-B41A-44A7-AF10-2D5462CE0162} = {4F5D77F3-B41A-44A7-AF10-2D5462CE0162} @@ -221,6 +222,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestSerializationHelpers", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestSerializationHelpers.Test", "tests\Agent\Shared\TestSerializationHelpers.Test\TestSerializationHelpers.Test.csproj", "{DC3E4801-A54A-42A4-AC45-DBD2F0CAE438}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AwsSdk", "src\Agent\NewRelic\Agent\Extensions\Providers\Wrapper\AwsSdk\AwsSdk.csproj", "{37262C22-6A3A-4AD7-AB78-3853D2B2931D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -467,6 +470,10 @@ Global {DC3E4801-A54A-42A4-AC45-DBD2F0CAE438}.Debug|Any CPU.Build.0 = Debug|Any CPU {DC3E4801-A54A-42A4-AC45-DBD2F0CAE438}.Release|Any CPU.ActiveCfg = Release|Any CPU {DC3E4801-A54A-42A4-AC45-DBD2F0CAE438}.Release|Any CPU.Build.0 = Release|Any CPU + {37262C22-6A3A-4AD7-AB78-3853D2B2931D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {37262C22-6A3A-4AD7-AB78-3853D2B2931D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {37262C22-6A3A-4AD7-AB78-3853D2B2931D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {37262C22-6A3A-4AD7-AB78-3853D2B2931D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -538,6 +545,7 @@ Global {C26170C8-0489-42F8-9579-EE8A06D65CC4} = {5E86E10A-C38F-48CB-ADE9-67B22BB2F50A} {173B1B8E-51D9-4639-88E9-B08065C2B47B} = {E5B988C0-5D19-407E-8210-71FFB90C579A} {DC3E4801-A54A-42A4-AC45-DBD2F0CAE438} = {E5B988C0-5D19-407E-8210-71FFB90C579A} + {37262C22-6A3A-4AD7-AB78-3853D2B2931D} = {5E86E10A-C38F-48CB-ADE9-67B22BB2F50A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.2\lib\NET35 diff --git a/build/ArtifactBuilder/CoreAgentComponents.cs b/build/ArtifactBuilder/CoreAgentComponents.cs index b82258bfb..bcaf0741b 100644 --- a/build/ArtifactBuilder/CoreAgentComponents.cs +++ b/build/ArtifactBuilder/CoreAgentComponents.cs @@ -61,6 +61,7 @@ protected override void CreateAgentComponents() $@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AspNetCore6Plus.dll", $@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Bedrock.dll", $@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AwsLambda.dll", + $@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AwsSdk.dll", }; var wrapperXmls = new[] @@ -86,6 +87,7 @@ protected override void CreateAgentComponents() $@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AspNetCore6Plus.Instrumentation.xml", $@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Bedrock.Instrumentation.xml", $@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AwsLambda.Instrumentation.xml", + $@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AwsSdk.Instrumentation.xml", }; ExtensionXsd = $@"{SourceHomeBuilderPath}\extensions\extension.xsd"; diff --git a/src/Agent/MsiInstaller/Installer/Product.wxs b/src/Agent/MsiInstaller/Installer/Product.wxs index 3a85254ec..af091d8fd 100644 --- a/src/Agent/MsiInstaller/Installer/Product.wxs +++ b/src/Agent/MsiInstaller/Installer/Product.wxs @@ -394,7 +394,9 @@ SPDX-License-Identifier: Apache-2.0 - + + + @@ -471,6 +473,9 @@ SPDX-License-Identifier: Apache-2.0 + + + @@ -587,6 +592,9 @@ SPDX-License-Identifier: Apache-2.0 + + + @@ -653,6 +661,9 @@ SPDX-License-Identifier: Apache-2.0 + + + diff --git a/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AwsSdk/AwsSdk.csproj b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AwsSdk/AwsSdk.csproj new file mode 100644 index 000000000..3c796cf2d --- /dev/null +++ b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AwsSdk/AwsSdk.csproj @@ -0,0 +1,20 @@ + + + net462;netstandard2.0 + NewRelic.Providers.Wrapper.AwsSdk + NewRelic.Providers.Wrapper.AwsSdk + AWS SDK Wrapper Provider for New Relic .NET Agent + + + + PreserveNewest + + + + + + + + + + \ No newline at end of file diff --git a/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AwsSdk/AwsSdkPipelineWrapper.cs b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AwsSdk/AwsSdkPipelineWrapper.cs new file mode 100644 index 000000000..0b3d92ec9 --- /dev/null +++ b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AwsSdk/AwsSdkPipelineWrapper.cs @@ -0,0 +1,63 @@ +// Copyright 2020 New Relic, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +using System; +using System.Linq; +using NewRelic.Agent.Api; +using NewRelic.Agent.Extensions.Providers.Wrapper; + +namespace NewRelic.Providers.Wrapper.AwsSdk +{ + public class AwsSdkPipelinekWrapper : IWrapper + { + public bool IsTransactionRequired => true; + + private const string WrapperName = "AwsSdkPipelineWrapper"; + + public CanWrapResponse CanWrap(InstrumentedMethodInfo methodInfo) + { + return new CanWrapResponse(WrapperName.Equals(methodInfo.RequestedWrapperName)); + } + + public AfterWrappedMethodDelegate BeforeWrappedMethod(InstrumentedMethodCall instrumentedMethodCall, IAgent agent, ITransaction transaction) + { + // Get the IExecutionContext (the only parameter) + dynamic executionContext = instrumentedMethodCall.MethodCall.MethodArguments[0]; + + // Get the IRequestContext + dynamic requestContext = executionContext.RequestContext; + + dynamic metadata = requestContext.ServiceMetaData; + string requestId = metadata.ServiceId; // SQS? + + // Get the AmazonWebServiceRequest being invoked. The name will tell us the type of request + dynamic request = requestContext.OriginalRequest; + string requestType = request.GetType().Name; + + // Get the web request object (IRequest). This can be used to get the headers + dynamic webRequest = requestContext.Request; + + ISegment segment; + + switch (requestType) + { + case "SendMessageRequest": + case "SendMessageBatchRequest": + segment = SqsHelper.GenerateSegment(transaction, instrumentedMethodCall.MethodCall, request.QueueUrl, MessageBrokerAction.Produce); + // This needs to happen at the end + //SqsHelper.InsertDistributedTraceHeaders(transaction, webRequest); + break; + case "ReceiveMessageRequest": + segment = SqsHelper.GenerateSegment(transaction, instrumentedMethodCall.MethodCall, request.QueueUrl, MessageBrokerAction.Consume); + break; + case "PurgeQueueRequest": + segment = SqsHelper.GenerateSegment(transaction, instrumentedMethodCall.MethodCall, request.QueueUrl, MessageBrokerAction.Purge); + break; + default: + return Delegates.NoOp; + } + + return Delegates.GetDelegateFor(segment); + } + } +} diff --git a/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AwsSdk/Instrumentation.xml b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AwsSdk/Instrumentation.xml new file mode 100644 index 000000000..c909ea4cd --- /dev/null +++ b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AwsSdk/Instrumentation.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AwsSdk/SqsHelper.cs b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AwsSdk/SqsHelper.cs new file mode 100644 index 000000000..3d3a5a3e7 --- /dev/null +++ b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AwsSdk/SqsHelper.cs @@ -0,0 +1,57 @@ +// Copyright 2020 New Relic, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.NetworkInformation; +using NewRelic.Agent.Api; +using NewRelic.Agent.Extensions.Providers.Wrapper; + +namespace NewRelic.Providers.Wrapper.AwsSdk +{ + public static class SqsHelper + { + public const string VendorName = "SQS"; + private class SqsAttributes + { + public string QueueName; + public string CloudId; + public string Region; + + // https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue + public SqsAttributes(string url) + { + var parts = url.Split('/'); + var subdomain = parts[2].Split('.'); + // subdomain[0] should always be "sqs" + Region = subdomain[1]; + CloudId = parts[3]; + QueueName = parts[4]; + } + } + public static ISegment GenerateSegment(ITransaction transaction, MethodCall methodCall, string url, MessageBrokerAction action) + { + var attr = new SqsAttributes(url); + return transaction.StartMessageBrokerSegment(methodCall, MessageBrokerDestinationType.Queue, action, VendorName, attr.QueueName); + } + + public static void InsertDistributedTraceHeaders(ITransaction transaction, dynamic webRequest) + { + var setHeaders = new Action((webRequest, key, value) => + { + var headers = webRequest.Headers as IDictionary; + + if (headers == null) + { + headers = new Dictionary(); + webRequest.Headers = headers; + } + + headers[key] = value; + }); + transaction.InsertDistributedTraceHeaders(webRequest, setHeaders); + + } + } +}