Skip to content

Commit

Permalink
improvements in CachedMessageHeadersHelpers
Browse files Browse the repository at this point in the history
I really wish I'd find a way to unify those two...
  • Loading branch information
vandonr committed Oct 31, 2024
1 parent aa4868e commit e70efef
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
/// <summary>
/// Allows the creation of MessageAttributes and MessageAttributeValue with a type corresponding to the one given as template parameter
/// </summary>
/// <typeparam name="TMarkerType">can be any type in the same assembly as the Attributes we want to create.</typeparam>
internal sealed class CachedMessageHeadersHelper<TMarkerType> : 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<MemoryStream, object> _createMessageAttributeValue;
private static readonly Func<IDictionary> _createDict;
// ReSharper disable StaticMemberInGenericType
// there will be one instance of those fields per template type
private static readonly Func<MemoryStream, object> MessageAttributeValueCreator;
private static readonly ActivatorHelper DictionaryActivator;
// ReSharper restore StaticMemberInGenericType

public static readonly CachedMessageHeadersHelper<TMarkerType> Instance = new();
public static readonly CachedMessageHeadersHelper<TMarkerType> Instance;

private CachedMessageHeadersHelper()
{
Expand Down Expand Up @@ -54,37 +64,24 @@ static CachedMessageHeadersHelper()

messageAttributeIL.Emit(OpCodes.Ret);

_createMessageAttributeValue = (Func<MemoryStream, object>)createMessageAttributeValueMethod.CreateDelegate(typeof(Func<MemoryStream, object>));
MessageAttributeValueCreator = (Func<MemoryStream, object>)createMessageAttributeValueMethod.CreateDelegate(typeof(Func<MemoryStream, object>));

// Initialize delegate for creating a Dictionary<string, MessageAttributeValue> 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<IDictionary>)createDictMethod.CreateDelegate(typeof(Func<IDictionary>));
Instance = new CachedMessageHeadersHelper<TMarkerType>();
}

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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,21 @@

namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.SQS
{
/// <summary>
/// Allows the creation of MessageAttributes and MessageAttributeValue with a type corresponding to the one given as template parameter
/// </summary>
/// <typeparam name="TMarkerType">can be any type in the same assembly as the Attributes we want to create.</typeparam>
internal sealed class CachedMessageHeadersHelper<TMarkerType> : IMessageHeadersHelper
{
private const string StringDataType = "String";

private static readonly Func<string, object> _createMessageAttributeValue;
// ReSharper disable StaticMemberInGenericType
// there will be one instance of those fields per template type
private static readonly Func<string, object> MessageAttributeValueCreator;
private static readonly ActivatorHelper DictionaryActivator;
// ReSharper restore StaticMemberInGenericType

public static readonly CachedMessageHeadersHelper<TMarkerType> Instance = new();
public static readonly CachedMessageHeadersHelper<TMarkerType> Instance;

private CachedMessageHeadersHelper()
{
Expand Down Expand Up @@ -52,10 +59,12 @@ static CachedMessageHeadersHelper()

messageAttributeIL.Emit(OpCodes.Ret);

_createMessageAttributeValue = (Func<string, object>)createMessageAttributeValueMethod.CreateDelegate(typeof(Func<string, object>));
MessageAttributeValueCreator = (Func<string, object>)createMessageAttributeValueMethod.CreateDelegate(typeof(Func<string, object>));

// Initialize delegate for creating a Dictionary<string, MessageAttributeValue> object
DictionaryActivator = new ActivatorHelper(typeof(Dictionary<,>).MakeGenericType(typeof(string), messageAttributeValueType));

Instance = new CachedMessageHeadersHelper<TMarkerType>();
}

public IDictionary CreateMessageAttributes()
Expand All @@ -65,7 +74,7 @@ public IDictionary CreateMessageAttributes()

public object CreateMessageAttributeValue(string value)
{
return _createMessageAttributeValue(value);
return MessageAttributeValueCreator(value);
}
}
}

0 comments on commit e70efef

Please sign in to comment.