diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SNS/CachedMessageHeadersHelper.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SNS/CachedMessageHeadersHelper.cs index e7721a9607a0..d06524b24735 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SNS/CachedMessageHeadersHelper.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SNS/CachedMessageHeadersHelper.cs @@ -12,17 +12,27 @@ using System.Text; using Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.Shared; using Datadog.Trace.DuckTyping; +using Datadog.Trace.Util; namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.SNS { + /// + /// Allows the creation of MessageAttributes and MessageAttributeValue with a type corresponding to the one given as template parameter + /// + /// can be any type in the same assembly as the Attributes we want to create. internal sealed class CachedMessageHeadersHelper : IMessageHeadersHelper { + // We have to use Binary for SNS because passing JSON payloads with String type makes subscription filter policies fail silently. + // see https://github.com/DataDog/datadog-lambda-js/pull/269 for more details. private const string StringDataType = "Binary"; - private static readonly Func _createMessageAttributeValue; - private static readonly Func _createDict; + // ReSharper disable StaticMemberInGenericType + // there will be one instance of those fields per template type + private static readonly Func MessageAttributeValueCreator; + private static readonly ActivatorHelper DictionaryActivator; + // ReSharper restore StaticMemberInGenericType - public static readonly CachedMessageHeadersHelper Instance = new(); + public static readonly CachedMessageHeadersHelper Instance; private CachedMessageHeadersHelper() { @@ -54,37 +64,24 @@ static CachedMessageHeadersHelper() messageAttributeIL.Emit(OpCodes.Ret); - _createMessageAttributeValue = (Func)createMessageAttributeValueMethod.CreateDelegate(typeof(Func)); + MessageAttributeValueCreator = (Func)createMessageAttributeValueMethod.CreateDelegate(typeof(Func)); // Initialize delegate for creating a Dictionary object - var genericDictType = typeof(Dictionary<,>); - var constructedDictType = genericDictType.MakeGenericType(new Type[] { typeof(string), messageAttributeValueType }); - ConstructorInfo dictionaryCtor = constructedDictType.GetConstructor(System.Type.EmptyTypes); + DictionaryActivator = new ActivatorHelper(typeof(Dictionary<,>).MakeGenericType(typeof(string), messageAttributeValueType)); - DynamicMethod createDictMethod = new DynamicMethod( - $"SnsCachedMessageHeadersHelpers", - constructedDictType, - null, - typeof(DuckType).Module, - true); - - ILGenerator dictIL = createDictMethod.GetILGenerator(); - dictIL.Emit(OpCodes.Newobj, dictionaryCtor); - dictIL.Emit(OpCodes.Ret); - - _createDict = (Func)createDictMethod.CreateDelegate(typeof(Func)); + Instance = new CachedMessageHeadersHelper(); } public IDictionary CreateMessageAttributes() { - return _createDict(); + return (IDictionary)DictionaryActivator.CreateInstance(); } public object CreateMessageAttributeValue(string value) { var bytes = Encoding.UTF8.GetBytes(value); var stream = new MemoryStream(bytes); - return _createMessageAttributeValue(stream); + return MessageAttributeValueCreator(stream); } } } diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SQS/CachedMessageHeadersHelper.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SQS/CachedMessageHeadersHelper.cs index 67a6d774f015..93a1cee8ec90 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SQS/CachedMessageHeadersHelper.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SQS/CachedMessageHeadersHelper.cs @@ -13,14 +13,21 @@ namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.SQS { + /// + /// Allows the creation of MessageAttributes and MessageAttributeValue with a type corresponding to the one given as template parameter + /// + /// can be any type in the same assembly as the Attributes we want to create. internal sealed class CachedMessageHeadersHelper : IMessageHeadersHelper { private const string StringDataType = "String"; - private static readonly Func _createMessageAttributeValue; + // ReSharper disable StaticMemberInGenericType + // there will be one instance of those fields per template type + private static readonly Func MessageAttributeValueCreator; private static readonly ActivatorHelper DictionaryActivator; + // ReSharper restore StaticMemberInGenericType - public static readonly CachedMessageHeadersHelper Instance = new(); + public static readonly CachedMessageHeadersHelper Instance; private CachedMessageHeadersHelper() { @@ -52,10 +59,12 @@ static CachedMessageHeadersHelper() messageAttributeIL.Emit(OpCodes.Ret); - _createMessageAttributeValue = (Func)createMessageAttributeValueMethod.CreateDelegate(typeof(Func)); + MessageAttributeValueCreator = (Func)createMessageAttributeValueMethod.CreateDelegate(typeof(Func)); // Initialize delegate for creating a Dictionary object DictionaryActivator = new ActivatorHelper(typeof(Dictionary<,>).MakeGenericType(typeof(string), messageAttributeValueType)); + + Instance = new CachedMessageHeadersHelper(); } public IDictionary CreateMessageAttributes() @@ -65,7 +74,7 @@ public IDictionary CreateMessageAttributes() public object CreateMessageAttributeValue(string value) { - return _createMessageAttributeValue(value); + return MessageAttributeValueCreator(value); } } }