Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Instrumentation for Amazon Simple Queuing Service (AWSSDK.SQS) #2620

Merged
merged 22 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e7b0bc7
First pass at SQS instrumentation
chynesNR Jun 6, 2024
bbe15fd
Merge from POC branch, resolve conflicts
tippmar-nr Jun 24, 2024
6489cd0
Remove outdated reference to NewRelic.Core
tippmar-nr Jun 24, 2024
1b6496c
Code cleanup, added some null checks
tippmar-nr Jun 24, 2024
c858368
A bit more refactoring
tippmar-nr Jun 24, 2024
9a0301c
Cleanup, minor refactor
tippmar-nr Jun 25, 2024
9e7eb21
Merge remote-tracking branch 'origin/main' into feature/sqs-instrumen…
tippmar-nr Jun 26, 2024
47f9d31
Fix merge error from main branch
tippmar-nr Jun 26, 2024
8fcbd28
Add AwsSdk to Framework components list
tippmar-nr Jun 26, 2024
0c944f4
test: Integration tests for SQS (#2577)
tippmar-nr Jun 28, 2024
ea3d88c
test: Adds a few more SQS calls to the container tests, update docker…
tippmar-nr Jun 28, 2024
875a90b
Minor bug fix, enables SQS v3.3.0 to work
tippmar-nr Jun 28, 2024
c4736c7
Logging tweak
tippmar-nr Jun 28, 2024
995b377
ci: Add AWSSDK.SQS package to Dotty's list
tippmar-nr Jul 2, 2024
4a6c869
SQS: Distributed Tracing support (#2591)
tippmar-nr Jul 2, 2024
43e62d8
Modify DT insertion to handle SendMessageBatchRequest
tippmar-nr Jul 3, 2024
8e90406
Additional tests for SQS (#2594)
tippmar-nr Jul 8, 2024
df8518c
Merge from main
tippmar-nr Jul 8, 2024
e44d44c
Merge branch 'feature/sqs-instrumentation' of https://github.com/newr…
tippmar-nr Jul 8, 2024
bc612cf
SQS: Rework distributed trace tests (#2602)
tippmar-nr Jul 11, 2024
814a557
Merge from main, resolve conflicts
tippmar-nr Jul 11, 2024
98c2135
chore: Refactor AwsSdkPipelineWrapper to encapsulate SQS handling (#2…
tippmar-nr Jul 11, 2024
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 @@ -29,6 +29,9 @@
{
"packageName": "amazon.lambda.sqsevents"
},
{
"packageName": "awssdk.sqs"
},
{
"packageName": "elasticsearch.net"
},
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,6 @@ tests/TestResults/*
/src/Agent/_profilerBuild/x86-Release/NewRelic.Profiler.dll
/tests/Agent/IntegrationTests/ContainerApplications/.env

/tests/Agent/IntegrationTests/LocalStack/volume
*.env
/tests/Agent/IntegrationTests/ContainerApplications/volume/cache
8 changes: 8 additions & 0 deletions FullAgent.sln
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,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}
Expand Down Expand Up @@ -211,6 +212,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
Expand Down Expand Up @@ -441,6 +444,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
Expand Down Expand Up @@ -508,6 +515,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
Expand Down
2 changes: 2 additions & 0 deletions build/ArtifactBuilder/CoreAgentComponents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,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[]
Expand All @@ -82,6 +83,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";
Expand Down
2 changes: 2 additions & 0 deletions build/ArtifactBuilder/FrameworkAgentComponents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ protected override void CreateAgentComponents()
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.MassTransitLegacy.dll",
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Kafka.dll",
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Bedrock.dll",
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AwsSdk.dll",
};

var wrapperXmls = new[]
Expand Down Expand Up @@ -103,6 +104,7 @@ protected override void CreateAgentComponents()
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.MassTransitLegacy.Instrumentation.xml",
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Kafka.Instrumentation.xml",
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Bedrock.Instrumentation.xml",
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AwsSdk.Instrumentation.xml",
};

ExtensionXsd = $@"{SourceHomeBuilderPath}\extensions\extension.xsd";
Expand Down
12 changes: 12 additions & 0 deletions src/Agent/MsiInstaller/Installer/Product.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,9 @@ SPDX-License-Identifier: Apache-2.0
<Component Id="BedrockWrapperComponent" Guid="{C913E912-97D1-4042-8E11-A35E04C6A6E5}">
<File Id="BedrockWrapperFile" Name="NewRelic.Providers.Wrapper.Bedrock.dll" KeyPath="yes" Source="$(var.HomeFolderPath)\extensions\NewRelic.Providers.Wrapper.Bedrock.dll" />
</Component>
<Component Id="AwsSdkWrapperComponent" Guid="{00D58C03-D517-41CA-BBAD-DAC605EADD3E}">
<File Id="AwsSdkWrapperFile" Name="NewRelic.Providers.Wrapper.AwsSdk.dll" KeyPath="yes" Source="$(var.HomeFolderPath)\extensions\NewRelic.Providers.Wrapper.AwsSdk.dll" />
</Component>
</ComponentGroup>

<ComponentGroup Id="CoreNewRelic.Agent.Extensions" Directory="CoreProgramFilesExtensionsFolder">
Expand Down Expand Up @@ -463,6 +466,9 @@ SPDX-License-Identifier: Apache-2.0
<Component Id="CoreAwsLambdaWrapperComponent" Guid="{778F507F-97D7-48B2-BE51-46D6DAB2D234}">
<File Id="CoreAwsLambdaWrapperFile" Name="NewRelic.Providers.Wrapper.AwsLambda.dll" KeyPath="yes" Source="$(var.HomeFolderPath)_coreclr\extensions\NewRelic.Providers.Wrapper.AwsLambda.dll"/>
</Component>
<Component Id="CoreAwsSdkWrapperComponent" Guid="{7C5E31CB-BA85-4E00-BA1B-99FA0B42E414}">
<File Id="CoreAwsSdkWrapperFile" Name="NewRelic.Providers.Wrapper.AwsSdk.dll" KeyPath="yes" Source="$(var.HomeFolderPath)_coreclr\extensions\NewRelic.Providers.Wrapper.AwsSdk.dll" />
</Component>
</ComponentGroup>

<!-- Wrapper Instrumentation Files-->
Expand Down Expand Up @@ -572,6 +578,9 @@ SPDX-License-Identifier: Apache-2.0
<Component Id="BedrockInstrumentationComponent" Guid="{D6F0A2D6-D8D5-4C61-8056-1C9AA4D07132}">
<File Id="BedrockInstrumentationFile" Name="NewRelic.Providers.Wrapper.Bedrock.Instrumentation.xml" KeyPath="yes" Source="$(var.HomeFolderPath)\extensions\NewRelic.Providers.Wrapper.Bedrock.Instrumentation.xml" />
</Component>
<Component Id="AwsSdkInstrumentationComponent" Guid="{E719FAC8-8D69-41EA-9395-B71868DA7449}">
<File Id="AwsSdkInstrumentationFile" Name="NewRelic.Providers.Wrapper.AwsSdk.Instrumentation.xml" KeyPath="yes" Source="$(var.HomeFolderPath)\extensions\NewRelic.Providers.Wrapper.AwsSdk.Instrumentation.xml" />
</Component>
</ComponentGroup>

<ComponentGroup Id="CoreNewRelic.Agent.Extensions.Instrumentation" Directory="CoreExtensionsFolder">
Expand Down Expand Up @@ -638,6 +647,9 @@ SPDX-License-Identifier: Apache-2.0
<Component Id="CoreAwsLambdaInstrumentationComponent" Guid="{FD3BEB1B-B093-4FF6-A1FA-76E621CF26D6}">
<File Id="CoreAwsLambdaInstrumentationFile" Name="NewRelic.Providers.Wrapper.AwsLambda.Instrumentation.xml" KeyPath="yes" Source="$(var.HomeFolderPath)_coreclr\extensions\NewRelic.Providers.Wrapper.AwsLambda.Instrumentation.xml"/>
</Component>
<Component Id="CoreAwsSdkInstrumentationComponent" Guid="{CAB15FAE-EF3F-4998-9376-56DA4E11BAEF}">
<File Id="CoreAwsSdkInstrumentationFile" Name="NewRelic.Providers.Wrapper.AwsSdk.Instrumentation.xml" KeyPath="yes" Source="$(var.HomeFolderPath)_coreclr\extensions\NewRelic.Providers.Wrapper.AwsSdk.Instrumentation.xml"/>
</Component>
</ComponentGroup>

<!-- Extensions XSD-->
Expand Down
17 changes: 17 additions & 0 deletions src/Agent/NewRelic/Agent/Core/Agent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,23 @@ public void RecordLlmEvent(string eventType, IDictionary<string, object> attribu
_customEventTransformer.Transform(eventType, attributes, transaction.Priority);
}

public List<string> GetConfiguredDTHeaders()
{
List<string> headers = [];
if (_configurationService.Configuration.DistributedTracingEnabled)
{
headers.Add(Constants.TraceParentHeaderKey);
headers.Add(Constants.TraceStateHeaderKey);

if (!_configurationService.Configuration.ExcludeNewrelicHeader)
{
headers.Add(Constants.DistributedTracePayloadKeyAllLower);
}
}

return headers;
}

public ISimpleSchedulingService SimpleSchedulingService
{
get { return _simpleSchedulingService; }
Expand Down
2 changes: 1 addition & 1 deletion src/Agent/NewRelic/Agent/Core/Config/Configuration.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -1224,7 +1224,7 @@
<xs:attribute name="excludeNewrelicHeader" type="xs:boolean" default="false">
<xs:annotation>
<xs:documentation>
Set this to true to disable adding of the newrelic header to outgoing requests. It is disabled by default.
Set this to true to exclude the newrelic header from outgoing requests. It is included by default.
</xs:documentation>
</xs:annotation>
</xs:attribute>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,7 @@ public interface IAgentExperimental
ISimpleSchedulingService SimpleSchedulingService { get; }

void RecordLlmEvent(string eventType, IDictionary<string, object> attributes);

List<string> GetConfiguredDTHeaders();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using NewRelic.Agent.Api;
using NewRelic.Agent.Api.Experimental;
using NewRelic.Agent.Extensions.Providers.Wrapper;
using NewRelic.Reflection;

namespace NewRelic.Agent.Extensions.AwsSdk
{
public static class SqsHelper
{
private static ConcurrentDictionary<Type, Func<object, IDictionary>> _getMessageAttributes = new();
private static Func<object> _messageAttributeValueTypeFactory;

public const string VendorName = "SQS";

private class SqsAttributes
{
public string QueueName { get; }
public string CloudId { get; }
public string Region { get; }

// https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue
public SqsAttributes(string url)
{
if (string.IsNullOrEmpty(url))
{
return;
}

var parts = url.Split('/');
if (parts.Length < 5)
{
return;
}

CloudId = parts[3];
QueueName = parts[4];

var subdomain = parts[2].Split('.');
if (subdomain.Length < 2)
{
return;
}

// subdomain[0] should always be "sqs"
Region = subdomain[1];
}
}
public static ISegment GenerateSegment(ITransaction transaction, MethodCall methodCall, string url, MessageBrokerAction action)
{
var attr = new SqsAttributes(url);
var segment = transaction.StartMessageBrokerSegment(methodCall, MessageBrokerDestinationType.Queue, action, VendorName, attr.QueueName);
segment.GetExperimentalApi().MakeLeaf();

return segment;
}

// SQS allows a maximum of 10 message attributes
private const int MaxSQSMessageAttributes = 10;

public static void InsertDistributedTraceHeaders(ITransaction transaction, object sendMessageRequest, int dtHeaderCount)
{
var headersInserted = 0;

var setHeaders = new Action<object, string, string>((smr, key, value) =>
{
var getMessageAttributes = _getMessageAttributes.GetOrAdd(smr.GetType(), t => VisibilityBypasser.Instance.GeneratePropertyAccessor<IDictionary>(t, "MessageAttributes"));
var messageAttributes = getMessageAttributes(smr);

// if we can't add all DT headers, don't add any
if ((messageAttributes.Count + dtHeaderCount - headersInserted) > MaxSQSMessageAttributes)
return;

// create a new MessageAttributeValue instance
var messageAttributeValueTypeFactory = _messageAttributeValueTypeFactory ??= VisibilityBypasser.Instance.GenerateTypeFactory(smr.GetType().Assembly.FullName, "Amazon.SQS.Model.MessageAttributeValue");
object newMessageAttributeValue = messageAttributeValueTypeFactory.Invoke();

var dataTypePropertySetter = VisibilityBypasser.Instance.GeneratePropertySetter<string>(newMessageAttributeValue, "DataType");
dataTypePropertySetter("String");

var stringValuePropertySetter = VisibilityBypasser.Instance.GeneratePropertySetter<string>(newMessageAttributeValue, "StringValue");
stringValuePropertySetter(value);

messageAttributes.Add(key, newMessageAttributeValue);

++headersInserted;
});

transaction.InsertDistributedTraceHeaders(sendMessageRequest, setHeaders);

}
public static void AcceptDistributedTraceHeaders(ITransaction transaction, dynamic messageAttributes)
{
var getHeaders = new Func<IDictionary, string, IEnumerable<string>>((maDict, key) =>
{
if (!maDict.Contains(key))
return [];

return [(string)((dynamic)maDict[key]).StringValue];
});

transaction.AcceptDistributedTraceHeaders((IDictionary)messageAttributes, getHeaders, TransportType.Queue);

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net462;netstandard2.0</TargetFrameworks>
<AssemblyName>NewRelic.Providers.Wrapper.AwsSdk</AssemblyName>
<RootNamespace>NewRelic.Providers.Wrapper.AwsSdk</RootNamespace>
<Description>AWS SDK Wrapper Provider for New Relic .NET Agent</Description>
</PropertyGroup>
<ItemGroup>
<Content Include="Instrumentation.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\NewRelic.Agent.Extensions\NewRelic.Agent.Extensions.csproj" />
</ItemGroup>
</Project>
Loading
Loading