Skip to content

Commit 9132d10

Browse files
Port changes from #1992 into the release/2.0 branch.
Additional changes include: - Move CreateScope method from ChannelHandlerIntegration.cs to WcfCommon.cs
1 parent 7f0d3fc commit 9132d10

File tree

47 files changed

+2953
-488
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2953
-488
lines changed

tracer/build/_build/PrepareRelease/CallTargetDefinitionSource.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public class CallTargetDefinitionSource
1717

1818
public string TargetMethod { get; init; }
1919

20+
public ushort[] TargetMethodArgumentsToLoad { get; init; }
21+
2022
public string[] TargetSignatureTypes { get; init; }
2123

2224
public ushort TargetMinimumMajor { get; init; }

tracer/build/_build/PrepareRelease/GenerateIntegrationDefinitions.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ from assemblyNames in GetPropertyValue<string[]>(attribute, "AssemblyNames")
9292
TargetAssembly = assemblyNames,
9393
TargetType = GetPropertyValue<string>(attribute, "TypeName"),
9494
TargetMethod = GetPropertyValue<string>(attribute, "MethodName"),
95+
TargetMethodArgumentsToLoad = (GetPropertyValue<ushort[]>(attribute, "TargetMethodArgumentsToLoad") ?? Enumerable.Empty<ushort>()).ToArray(),
9596
TargetSignatureTypes = new string[] { GetPropertyValue<string>(attribute, "ReturnTypeName") }
9697
.Concat(GetPropertyValue<string[]>(attribute, "ParameterTypeNames") ?? Enumerable.Empty<string>())
9798
.ToArray(),
@@ -148,6 +149,28 @@ static void WriteCallTargetDefinitionFile(StreamWriter swriter, IEnumerable<Call
148149

149150
swriter.Write(" }, ");
150151

152+
if (integration.TargetMethodArgumentsToLoad.Length > 0)
153+
{
154+
swriter.Write($" new ushort[] {{ ");
155+
for (var s = 0; s < integration.TargetMethodArgumentsToLoad.Length; s++)
156+
{
157+
if (s == integration.TargetMethodArgumentsToLoad.Length - 1)
158+
{
159+
swriter.Write($"{integration.TargetMethodArgumentsToLoad[s]}");
160+
}
161+
else
162+
{
163+
swriter.Write($"{integration.TargetMethodArgumentsToLoad[s]}, ");
164+
}
165+
}
166+
167+
swriter.Write(" }, ");
168+
}
169+
else
170+
{
171+
swriter.Write("null, ");
172+
}
173+
151174
swriter.Write($"{integration.TargetMinimumMajor}, ");
152175
swriter.Write($"{integration.TargetMinimumMinor}, ");
153176
swriter.Write($"{integration.TargetMinimumPatch}, ");

tracer/src/Datadog.Trace.ClrProfiler.Native/calltarget_tokens.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,8 @@ HRESULT CallTargetTokens::ModifyLocalSigAndInitialize(void* rewriterWrapperPtr,
873873

874874
HRESULT CallTargetTokens::WriteBeginMethod(void* rewriterWrapperPtr, mdTypeRef integrationTypeRef,
875875
const TypeInfo* currentType,
876-
std::vector<FunctionMethodArgument>& methodArguments, ILInstr** instruction)
876+
const std::vector<FunctionMethodArgument>& methodArguments,
877+
const std::vector<USHORT>& argsToLoad, ILInstr** instruction)
877878
{
878879
auto hr = EnsureBaseCalltargetTokens();
879880
if (FAILED(hr))
@@ -884,7 +885,9 @@ HRESULT CallTargetTokens::WriteBeginMethod(void* rewriterWrapperPtr, mdTypeRef i
884885
ILRewriterWrapper* rewriterWrapper = (ILRewriterWrapper*) rewriterWrapperPtr;
885886
ModuleMetadata* module_metadata = GetMetadata();
886887

887-
auto numArguments = (int) methodArguments.size();
888+
auto numArgsToLoad = argsToLoad.size();
889+
bool useArgToLoad = numArgsToLoad > 0;
890+
auto numArguments = useArgToLoad ? (int) numArgsToLoad : (int) methodArguments.size();
888891
if (numArguments >= FASTPATH_COUNT)
889892
{
890893
return WriteBeginMethodWithArgumentsArray(rewriterWrapperPtr, integrationTypeRef, currentType, instruction);
@@ -947,7 +950,17 @@ HRESULT CallTargetTokens::WriteBeginMethod(void* rewriterWrapperPtr, mdTypeRef i
947950
ULONG argumentsSignatureSize[FASTPATH_COUNT];
948951
for (auto i = 0; i < numArguments; i++)
949952
{
950-
auto signatureSize = methodArguments[i].GetSignature(argumentsSignatureBuffer[i]);
953+
FunctionMethodArgument methodArgument;
954+
if (useArgToLoad)
955+
{
956+
methodArgument = methodArguments[argsToLoad[i]];
957+
}
958+
else
959+
{
960+
methodArgument = methodArguments[i];
961+
}
962+
963+
auto signatureSize = methodArgument.GetSignature(argumentsSignatureBuffer[i]);
951964
argumentsSignatureSize[i] = signatureSize;
952965
signatureLength += signatureSize;
953966
}

tracer/src/Datadog.Trace.ClrProfiler.Native/calltarget_tokens.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ class CallTargetTokens
8686
mdToken* callTargetReturnToken, ILInstr** firstInstruction);
8787

8888
HRESULT WriteBeginMethod(void* rewriterWrapperPtr, mdTypeRef integrationTypeRef, const TypeInfo* currentType,
89-
std::vector<FunctionMethodArgument>& methodArguments, ILInstr** instruction);
89+
const std::vector<FunctionMethodArgument>& methodArguments, const std::vector<USHORT>& argsToLoad,
90+
ILInstr** instruction);
9091

9192
HRESULT WriteEndVoidReturnMemberRef(void* rewriterWrapperPtr, mdTypeRef integrationTypeRef,
9293
const TypeInfo* currentType, ILInstr** instruction);

tracer/src/Datadog.Trace.ClrProfiler.Native/cor_profiler.cpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,14 @@ void CorProfiler::InitializeProfiler(WCHAR* id, CallTargetDefinition* items, int
956956
const WSTRING& integrationAssembly = WSTRING(current.integrationAssembly);
957957
const WSTRING& integrationType = WSTRING(current.integrationType);
958958

959+
bool useTargetMethodArgumentsToLoad = current.useTargetMethodArgumentsToLoad;
960+
std::vector<USHORT> targetMethodArgumentsToLoad;
961+
for (int sIdx = 0; sIdx < current.targetMethodArgumentsToLoadLength; sIdx++)
962+
{
963+
const auto currentArgumentIndex = current.targetMethodArgumentsToLoad[sIdx];
964+
targetMethodArgumentsToLoad.push_back(currentArgumentIndex);
965+
}
966+
959967
std::vector<WSTRING> signatureTypes;
960968
for (int sIdx = 0; sIdx < current.signatureTypesLength; sIdx++)
961969
{
@@ -972,7 +980,7 @@ void CorProfiler::InitializeProfiler(WCHAR* id, CallTargetDefinition* items, int
972980
Version(current.targetMaximumMajor, current.targetMaximumMinor, current.targetMaximumPatch, 0);
973981

974982
const auto& integration = IntegrationDefinition(
975-
MethodReference(targetAssembly, targetType, targetMethod, minVersion, maxVersion, signatureTypes),
983+
MethodReference(targetAssembly, targetType, targetMethod, minVersion, maxVersion, signatureTypes, useTargetMethodArgumentsToLoad, targetMethodArgumentsToLoad),
976984
TypeReference(integrationAssembly, integrationType, {}, {}));
977985

978986
if (Logger::IsDebugEnabled())
@@ -2462,7 +2470,11 @@ HRESULT CorProfiler::CallTarget_RewriterCallback(RejitHandlerModule* moduleHandl
24622470
bool isVoid = (retTypeFlags & TypeFlagVoid) > 0;
24632471
bool isStatic = !(caller->method_signature.CallingConvention() & IMAGE_CEE_CS_CALLCONV_HASTHIS);
24642472
std::vector<FunctionMethodArgument> methodArguments = caller->method_signature.GetMethodArguments();
2465-
int numArgs = caller->method_signature.NumberOfArguments();
2473+
bool useCustomArgumentsTargetMethodArguments = integration_definition->target_method.use_target_method_arguments_to_load;
2474+
std::vector<USHORT> methodArgumentsToLoad = integration_definition->target_method.target_method_arguments_to_load;
2475+
int numArgs = useCustomArgumentsTargetMethodArguments
2476+
? (int) methodArgumentsToLoad.size()
2477+
: caller->method_signature.NumberOfArguments();
24662478
auto metaEmit = module_metadata.metadata_emit;
24672479
auto metaImport = module_metadata.metadata_import;
24682480

@@ -2587,8 +2599,11 @@ HRESULT CorProfiler::CallTarget_RewriterCallback(RejitHandlerModule* moduleHandl
25872599
// Load the arguments directly (FastPath)
25882600
for (int i = 0; i < numArgs; i++)
25892601
{
2590-
reWriterWrapper.LoadArgument(i + (isStatic ? 0 : 1));
2591-
const auto& argTypeFlags = methodArguments[i].GetTypeFlags(elementType);
2602+
int loadIndex = useCustomArgumentsTargetMethodArguments
2603+
? methodArgumentsToLoad[i]
2604+
: i;
2605+
reWriterWrapper.LoadArgument(loadIndex + (isStatic ? 0 : 1));
2606+
const auto& argTypeFlags = methodArguments[loadIndex].GetTypeFlags(elementType);
25922607
if (argTypeFlags & TypeFlagByRef)
25932608
{
25942609
Logger::Warn("*** CallTarget_RewriterCallback(): Methods with ref parameters "
@@ -2604,8 +2619,12 @@ HRESULT CorProfiler::CallTarget_RewriterCallback(RejitHandlerModule* moduleHandl
26042619
for (int i = 0; i < numArgs; i++)
26052620
{
26062621
reWriterWrapper.BeginLoadValueIntoArray(i);
2607-
reWriterWrapper.LoadArgument(i + (isStatic ? 0 : 1));
2608-
const auto& argTypeFlags = methodArguments[i].GetTypeFlags(elementType);
2622+
2623+
int loadIndex = useCustomArgumentsTargetMethodArguments
2624+
? methodArgumentsToLoad[i]
2625+
: i;
2626+
reWriterWrapper.LoadArgument(loadIndex + (isStatic ? 0 : 1));
2627+
const auto& argTypeFlags = methodArguments[loadIndex].GetTypeFlags(elementType);
26092628
if (argTypeFlags & TypeFlagByRef)
26102629
{
26112630
Logger::Warn("*** CallTarget_RewriterCallback(): Methods with ref parameters "
@@ -2614,7 +2633,7 @@ HRESULT CorProfiler::CallTarget_RewriterCallback(RejitHandlerModule* moduleHandl
26142633
}
26152634
if (argTypeFlags & TypeFlagBoxedType)
26162635
{
2617-
const auto& tok = methodArguments[i].GetTypeTok(metaEmit, callTargetTokens->GetCorLibAssemblyRef());
2636+
const auto& tok = methodArguments[loadIndex].GetTypeTok(metaEmit, callTargetTokens->GetCorLibAssemblyRef());
26182637
if (tok == mdTokenNil)
26192638
{
26202639
return S_FALSE;
@@ -2661,6 +2680,7 @@ HRESULT CorProfiler::CallTarget_RewriterCallback(RejitHandlerModule* moduleHandl
26612680

26622681
ILInstr* beginCallInstruction;
26632682
hr = callTargetTokens->WriteBeginMethod(&reWriterWrapper, integration_type_ref, &caller->type, methodArguments,
2683+
methodArgumentsToLoad,
26642684
&beginCallInstruction);
26652685
if (FAILED(hr))
26662686
{

tracer/src/Datadog.Trace.ClrProfiler.Native/integration.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,17 +275,23 @@ struct MethodReference
275275
const TypeReference type;
276276
const WSTRING method_name;
277277
const std::vector<WSTRING> signature_types;
278+
const bool use_target_method_arguments_to_load;
279+
const std::vector<USHORT> target_method_arguments_to_load;
278280

279-
MethodReference()
281+
MethodReference() :
282+
use_target_method_arguments_to_load(false)
280283
{
281284
}
282285

283286
MethodReference(const WSTRING& assembly_name, WSTRING type_name, WSTRING method_name,
284287
Version min_version, Version max_version,
285-
const std::vector<WSTRING>& signature_types) :
288+
const std::vector<WSTRING>& signature_types, bool use_target_method_arguments_to_load,
289+
const std::vector<USHORT>& target_method_arguments_to_load) :
286290
type(assembly_name, type_name, min_version, max_version),
287291
method_name(method_name),
288-
signature_types(signature_types)
292+
signature_types(signature_types),
293+
use_target_method_arguments_to_load(use_target_method_arguments_to_load),
294+
target_method_arguments_to_load(target_method_arguments_to_load)
289295
{
290296
}
291297

@@ -322,6 +328,9 @@ typedef struct _CallTargetDefinition
322328
WCHAR* targetMethod;
323329
WCHAR** signatureTypes;
324330
USHORT signatureTypesLength;
331+
bool useTargetMethodArgumentsToLoad;
332+
USHORT* targetMethodArgumentsToLoad;
333+
USHORT targetMethodArgumentsToLoadLength;
325334
USHORT targetMinimumMajor;
326335
USHORT targetMinimumMinor;
327336
USHORT targetMinimumPatch;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// <copyright file="AsyncMethodInvoker_InvokeBegin_Integration.cs" company="Datadog">
2+
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
4+
// </copyright>
5+
6+
#if NETFRAMEWORK
7+
using System;
8+
using System.ComponentModel;
9+
using System.Reflection;
10+
using Datadog.Trace.ClrProfiler.CallTarget;
11+
using Datadog.Trace.ClrProfiler.Emit;
12+
using Datadog.Trace.Configuration;
13+
14+
namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.Wcf
15+
{
16+
/// <summary>
17+
/// System.ServiceModel.Dispatcher.AsyncMethodInvoker calltarget instrumentation
18+
/// </summary>
19+
[InstrumentMethod(
20+
AssemblyName = "System.ServiceModel",
21+
TypeName = "System.ServiceModel.Dispatcher.AsyncMethodInvoker",
22+
MethodName = "InvokeBegin",
23+
ReturnTypeName = ClrNames.IAsyncResult,
24+
ParameterTypeNames = new[] { ClrNames.Object, "System.Object[]", ClrNames.AsyncCallback, ClrNames.Object },
25+
MinimumVersion = "4.0.0",
26+
MaximumVersion = "4.*.*",
27+
IntegrationName = WcfCommon.IntegrationName)]
28+
[Browsable(false)]
29+
[EditorBrowsable(EditorBrowsableState.Never)]
30+
public class AsyncMethodInvoker_InvokeBegin_Integration
31+
{
32+
/// <summary>
33+
/// OnMethodBegin callback
34+
/// </summary>
35+
/// <typeparam name="TTarget">Type of the target</typeparam>
36+
/// <param name="instance">Instance value, aka `this` of the instrumented method.</param>
37+
/// <param name="instanceArg">RequestContext instance</param>
38+
/// <param name="inputs">Input arguments</param>
39+
/// <param name="callback">Callback argument</param>
40+
/// <param name="state">State argument</param>
41+
/// <returns>Calltarget state value</returns>
42+
public static CallTargetState OnMethodBegin<TTarget>(TTarget instance, object instanceArg, object[] inputs, AsyncCallback callback, object state)
43+
{
44+
// TODO Just use the OperationContext.Current object to get the span information
45+
// context.IncomingMessageHeaders contains:
46+
// - Action
47+
// - To
48+
//
49+
// context.IncomingMessageProperties contains:
50+
// - ["httpRequest"] key to find distributed tracing headers
51+
if (!Tracer.Instance.Settings.IsIntegrationEnabled(WcfCommon.IntegrationId) || !Tracer.Instance.Settings.DelayWcfInstrumentationEnabled || WcfCommon.GetCurrentOperationContext is null)
52+
{
53+
return CallTargetState.GetDefault();
54+
}
55+
56+
var requestContext = WcfCommon.GetCurrentOperationContext()?.GetProperty<object>("RequestContext").GetValueOrDefault();
57+
return new CallTargetState(WcfCommon.CreateScope(requestContext));
58+
}
59+
}
60+
}
61+
#endif
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// <copyright file="AsyncMethodInvoker_InvokeEnd_Integration.cs" company="Datadog">
2+
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
4+
// </copyright>
5+
6+
#if NETFRAMEWORK
7+
using System;
8+
using System.ComponentModel;
9+
using System.Reflection;
10+
using Datadog.Trace.ClrProfiler.CallTarget;
11+
using Datadog.Trace.Configuration;
12+
13+
namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.Wcf
14+
{
15+
/// <summary>
16+
/// System.ServiceModel.Dispatcher.AsyncMethodInvoker calltarget instrumentation
17+
/// </summary>
18+
[InstrumentMethod(
19+
AssemblyName = "System.ServiceModel",
20+
TypeName = "System.ServiceModel.Dispatcher.AsyncMethodInvoker",
21+
MethodName = "InvokeEnd",
22+
ReturnTypeName = ClrNames.Object,
23+
ParameterTypeNames = new[] { ClrNames.Object, "System.Object[]&", ClrNames.IAsyncResult },
24+
TargetMethodArgumentsToLoad = new ushort[] { 0, 2 }, // DO NOT pass the "out object[]" parameter into the instrumentation method
25+
MinimumVersion = "4.0.0",
26+
MaximumVersion = "4.*.*",
27+
IntegrationName = WcfCommon.IntegrationName)]
28+
[Browsable(false)]
29+
[EditorBrowsable(EditorBrowsableState.Never)]
30+
public class AsyncMethodInvoker_InvokeEnd_Integration
31+
{
32+
/// <summary>
33+
/// OnMethodEnd callback
34+
/// </summary>
35+
/// <typeparam name="TTarget">Type of the target</typeparam>
36+
/// <typeparam name="TReturn">Type of the response</typeparam>
37+
/// <param name="instance">Instance value, aka `this` of the instrumented method.</param>
38+
/// <param name="returnValue">Return value</param>
39+
/// <param name="exception">Exception instance in case the original code threw an exception.</param>
40+
/// <param name="state">Calltarget state value</param>
41+
/// <returns>A response value, in an async scenario will be T of Task of T</returns>
42+
public static CallTargetReturn<TReturn> OnMethodEnd<TTarget, TReturn>(TTarget instance, TReturn returnValue, Exception exception, CallTargetState state)
43+
{
44+
var scope = Tracer.Instance.ActiveScope;
45+
scope.DisposeWithException(exception);
46+
return new CallTargetReturn<TReturn>(returnValue);
47+
}
48+
}
49+
}
50+
#endif

0 commit comments

Comments
 (0)