Skip to content

Commit d009bf0

Browse files
Add modified WCF CallTarget instrumentation via opt-in environment variable (#1992)
* Changes to Samples.Wcf and the corresponding WcfTests Xunit tests - Add a new Custom binding that will throw an exception when accessing the RequestMessage, similar to what we've seen in production - Test all 4 bindings in the integration tests - Update WcfTests to use snapshot testing - Create test cases for the new WCF tracing mode, enabled by setting DD_TRACE_WCF_ENABLE_NEW_INSTRUMENTATION=true * Small WCF integration fix: Do not access the request message if the WCF integration is disabled * Update automatic instrumentation contract to allow for TargetMethodArgumentsToLoad and TargetMethodArgumentsToLoadLength properties. This allows the OnBegin method to use a subset of the instrumented method's parameters, allowing us to instrument methods with ref arguments * Make tracer changes to accept the new DD_TRACE_WCF_ENABLE_NEW_INSTRUMENTATION setting, disable original WCF instrumentation when DD_TRACE_WCF_ENABLE_NEW_INSTRUMENTATION=true, and update tests/snapshots * Add new instrumentation for System.ServiceModel.Dispatcher.SyncMethodInvoker and update snapshots * Add new instrumentation for System.ServiceModel.Dispatcher.TaskMethodInvoker and update snapshots * Add new instrumentation for System.Servicemodel.Dispatcher.AsyncMethodInvoker and update snapshots. IMPORTANT: Does not work with TcpBinding; OnMethodEnd for the InvokeEnd operation does not detect ambient Scope * - Consolidate GetCurrentOperationContext delegate into a property in the WcfCommon.cs class (intentionally new file to avoid rename conflicts with existing WcfIntegration.cs) - Populate the GetCurrentOperationContext delegate lazily - Check that the WCF integration is enabled and the feature flag is enabled FIRST, before checking whether the GetCurrentOperationContext is non-null * - Change the environment variable name to DD_TRACE_DELAY_WCF_INSTRUMENTATION_ENABLED - Move the DelayWcfInstrumentationEnabled to the FeatureFlags grouping of ConfigurationKeys - Make the DelayWcfInstrumentationEnabled TracerSetting internal * In WcfTests, remove silly, incorrect comment * Free the native memory associated with the new TargetMethodArgumentsToLoad array in the Marshal'ed NativeCallTargetDefinition * - Generate null instead of empty ushort arrays when generating integration definitions that do not override the TargetMethodArgumentsToLoad array - Add additional bool field in NativeCallTargetDefinition to disambiguate between "Don't use the TargetMethodArgumentsToLoad feature" and "Use the feature but don't pass any arguments" * Optimization: Make the methodArguments and argsToLoad arguments to WriteBeginMethod constant * Fix WcfTest to use the updated environment variable name DD_TRACE_DELAY_WCF_INSTRUMENTATION_ENABLED * Fix silly typo in environment variable name * For Samples.Wcf: Refactor CustomBindingElement and other required classes into a Bindings/Custom folder, and suppress CS0067 build warning * Fix the native Windows tests * Add some logging changes to Samples.Wcf to help understand why we're hanging and getting unpredictable snapshots * Last ditch effort, increase the timeout in WcfTests so we wait 60s max instead of 20s max for spans to reach the MockTracerAgent, in hopes that it fixes the flakiness in the snapshot tests where some snapshots don't have all expected spans. * Temporarily disable the server async (Begin/End) testing because it is flaky in CI where it does not consistently emit the server spans. Reset the snapshots to exclude the Async spans for now. Note: This didn't affect the NetTcpBinding with the new instrumentation because the Async endpoint wasn't working, and it didn't affect the CustomBinding because that doesn't return any spans.
1 parent 1a05a56 commit d009bf0

File tree

50 files changed

+2867
-402
lines changed

Some content is hidden

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

50 files changed

+2867
-402
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
@@ -130,6 +130,7 @@ from assemblyNames in GetPropertyValue<string[]>(attribute, "AssemblyNames")
130130
TargetAssembly = assemblyNames,
131131
TargetType = GetPropertyValue<string>(attribute, "TypeName"),
132132
TargetMethod = GetPropertyValue<string>(attribute, "MethodName"),
133+
TargetMethodArgumentsToLoad = (GetPropertyValue<ushort[]>(attribute, "TargetMethodArgumentsToLoad") ?? Enumerable.Empty<ushort>()).ToArray(),
133134
TargetSignatureTypes = new string[] { GetPropertyValue<string>(attribute, "ReturnTypeName") }
134135
.Concat(GetPropertyValue<string[]>(attribute, "ParameterTypeNames") ?? Enumerable.Empty<string>())
135136
.ToArray(),
@@ -187,6 +188,28 @@ static void WriteCallTargetDefinitionFile(StreamWriter swriter, IEnumerable<Call
187188

188189
swriter.Write(" }, ");
189190

191+
if (integration.TargetMethodArgumentsToLoad.Length > 0)
192+
{
193+
swriter.Write($" new ushort[] {{ ");
194+
for (var s = 0; s < integration.TargetMethodArgumentsToLoad.Length; s++)
195+
{
196+
if (s == integration.TargetMethodArgumentsToLoad.Length - 1)
197+
{
198+
swriter.Write($"{integration.TargetMethodArgumentsToLoad[s]}");
199+
}
200+
else
201+
{
202+
swriter.Write($"{integration.TargetMethodArgumentsToLoad[s]}, ");
203+
}
204+
}
205+
206+
swriter.Write(" }, ");
207+
}
208+
else
209+
{
210+
swriter.Write("null, ");
211+
}
212+
190213
swriter.Write($"{integration.TargetMinimumMajor}, ");
191214
swriter.Write($"{integration.TargetMinimumMinor}, ");
192215
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: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,14 @@ void CorProfiler::InitializeProfiler(WCHAR* id, CallTargetDefinition* items, int
12511251
wrapperType = WSTRING(current.wrapperType);
12521252
}
12531253

1254+
bool useTargetMethodArgumentsToLoad = current.useTargetMethodArgumentsToLoad;
1255+
std::vector<USHORT> targetMethodArgumentsToLoad;
1256+
for (int sIdx = 0; sIdx < current.targetMethodArgumentsToLoadLength; sIdx++)
1257+
{
1258+
const auto currentArgumentIndex = current.targetMethodArgumentsToLoad[sIdx];
1259+
targetMethodArgumentsToLoad.push_back(currentArgumentIndex);
1260+
}
1261+
12541262
std::vector<WSTRING> signatureTypes;
12551263
for (int sIdx = 0; sIdx < current.signatureTypesLength; sIdx++)
12561264
{
@@ -1271,9 +1279,9 @@ void CorProfiler::InitializeProfiler(WCHAR* id, CallTargetDefinition* items, int
12711279
MethodReplacement(
12721280
{},
12731281
MethodReference(targetAssembly, targetType, targetMethod, EmptyWStr, minVersion, maxVersion,
1274-
{}, signatureTypes),
1282+
{}, signatureTypes, useTargetMethodArgumentsToLoad, targetMethodArgumentsToLoad),
12751283
MethodReference(wrapperAssembly, wrapperType, EmptyWStr, calltarget_modification_action, {}, {}, {},
1276-
{})));
1284+
{}, false, {})));
12771285

12781286
if (Logger::IsDebugEnabled())
12791287
{
@@ -3432,7 +3440,11 @@ HRESULT CorProfiler::CallTarget_RewriterCallback(RejitHandlerModule* moduleHandl
34323440
bool isVoid = (retTypeFlags & TypeFlagVoid) > 0;
34333441
bool isStatic = !(caller->method_signature.CallingConvention() & IMAGE_CEE_CS_CALLCONV_HASTHIS);
34343442
std::vector<FunctionMethodArgument> methodArguments = caller->method_signature.GetMethodArguments();
3435-
int numArgs = caller->method_signature.NumberOfArguments();
3443+
bool useCustomArgumentsTargetMethodArguments = method_replacement->target_method.use_target_method_arguments_to_load;
3444+
std::vector<USHORT> methodArgumentsToLoad = method_replacement->target_method.target_method_arguments_to_load;
3445+
int numArgs = useCustomArgumentsTargetMethodArguments
3446+
? (int) methodArgumentsToLoad.size()
3447+
: caller->method_signature.NumberOfArguments();
34363448
auto metaEmit = module_metadata->metadata_emit;
34373449
auto metaImport = module_metadata->metadata_import;
34383450

@@ -3547,8 +3559,11 @@ HRESULT CorProfiler::CallTarget_RewriterCallback(RejitHandlerModule* moduleHandl
35473559
// Load the arguments directly (FastPath)
35483560
for (int i = 0; i < numArgs; i++)
35493561
{
3550-
reWriterWrapper.LoadArgument(i + (isStatic ? 0 : 1));
3551-
auto argTypeFlags = methodArguments[i].GetTypeFlags(elementType);
3562+
int loadIndex = useCustomArgumentsTargetMethodArguments
3563+
? methodArgumentsToLoad[i]
3564+
: i;
3565+
reWriterWrapper.LoadArgument(loadIndex + (isStatic ? 0 : 1));
3566+
auto argTypeFlags = methodArguments[loadIndex].GetTypeFlags(elementType);
35523567
if (argTypeFlags & TypeFlagByRef)
35533568
{
35543569
Logger::Warn("*** CallTarget_RewriterCallback(): Methods with ref parameters "
@@ -3564,8 +3579,12 @@ HRESULT CorProfiler::CallTarget_RewriterCallback(RejitHandlerModule* moduleHandl
35643579
for (int i = 0; i < numArgs; i++)
35653580
{
35663581
reWriterWrapper.BeginLoadValueIntoArray(i);
3567-
reWriterWrapper.LoadArgument(i + (isStatic ? 0 : 1));
3568-
auto argTypeFlags = methodArguments[i].GetTypeFlags(elementType);
3582+
3583+
int loadIndex = useCustomArgumentsTargetMethodArguments
3584+
? methodArgumentsToLoad[i]
3585+
: i;
3586+
reWriterWrapper.LoadArgument(loadIndex + (isStatic ? 0 : 1));
3587+
auto argTypeFlags = methodArguments[loadIndex].GetTypeFlags(elementType);
35693588
if (argTypeFlags & TypeFlagByRef)
35703589
{
35713590
Logger::Warn("*** CallTarget_RewriterCallback(): Methods with ref parameters "
@@ -3574,7 +3593,7 @@ HRESULT CorProfiler::CallTarget_RewriterCallback(RejitHandlerModule* moduleHandl
35743593
}
35753594
if (argTypeFlags & TypeFlagBoxedType)
35763595
{
3577-
auto tok = methodArguments[i].GetTypeTok(metaEmit, callTargetTokens->GetCorLibAssemblyRef());
3596+
auto tok = methodArguments[loadIndex].GetTypeTok(metaEmit, callTargetTokens->GetCorLibAssemblyRef());
35783597
if (tok == mdTokenNil)
35793598
{
35803599
return S_FALSE;
@@ -3621,6 +3640,7 @@ HRESULT CorProfiler::CallTarget_RewriterCallback(RejitHandlerModule* moduleHandl
36213640

36223641
ILInstr* beginCallInstruction;
36233642
hr = callTargetTokens->WriteBeginMethod(&reWriterWrapper, wrapper_type_ref, &caller->type, methodArguments,
3643+
methodArgumentsToLoad,
36243644
&beginCallInstruction);
36253645
if (FAILED(hr))
36263646
{

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,23 +247,27 @@ struct MethodReference
247247
const Version min_version;
248248
const Version max_version;
249249
const std::vector<WSTRING> signature_types;
250+
const bool use_target_method_arguments_to_load;
251+
const std::vector<USHORT> target_method_arguments_to_load;
250252

251253
MethodReference() :
252-
min_version(Version(0, 0, 0, 0)), max_version(Version(USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX))
254+
min_version(Version(0, 0, 0, 0)), max_version(Version(USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX)), use_target_method_arguments_to_load(false)
253255
{
254256
}
255257

256258
MethodReference(const WSTRING& assembly_name, WSTRING type_name, WSTRING method_name, WSTRING action,
257259
Version min_version, Version max_version, const std::vector<BYTE>& method_signature,
258-
const std::vector<WSTRING>& signature_types) :
260+
const std::vector<WSTRING>& signature_types, const bool use_target_method_arguments_to_load, const std::vector<USHORT>& target_method_arguments_to_load) :
259261
assembly(*AssemblyReference::GetFromCache(assembly_name)),
260262
type_name(type_name),
261263
method_name(method_name),
262264
action(action),
263265
method_signature(method_signature),
264266
min_version(min_version),
265267
max_version(max_version),
266-
signature_types(signature_types)
268+
signature_types(signature_types),
269+
use_target_method_arguments_to_load(use_target_method_arguments_to_load),
270+
target_method_arguments_to_load(target_method_arguments_to_load)
267271
{
268272
}
269273

@@ -336,6 +340,9 @@ typedef struct _CallTargetDefinition
336340
WCHAR* targetMethod;
337341
WCHAR** signatureTypes;
338342
USHORT signatureTypesLength;
343+
bool useTargetMethodArgumentsToLoad;
344+
USHORT* targetMethodArgumentsToLoad;
345+
USHORT targetMethodArgumentsToLoadLength;
339346
USHORT targetMinimumMajor;
340347
USHORT targetMinimumMinor;
341348
USHORT targetMinimumPatch;

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ namespace
212212
USHORT max_minor = USHRT_MAX;
213213
USHORT max_patch = USHRT_MAX;
214214
std::vector<WSTRING> signature_type_array;
215+
std::vector<USHORT> target_method_arguments_to_load_array; // Do not populate this because this only applies to CallTarget and we no longer use integrations.json
215216
WSTRING action = EmptyWStr;
216217

217218
if (is_target_method)
@@ -306,7 +307,7 @@ namespace
306307
}
307308
}
308309
return MethodReference(assembly, type, method, action, Version(min_major, min_minor, min_patch, 0),
309-
Version(max_major, max_minor, max_patch, USHRT_MAX), signature, signature_type_array);
310+
Version(max_major, max_minor, max_patch, USHRT_MAX), signature, signature_type_array, false, target_method_arguments_to_load_array);
310311
}
311312

312313
} // namespace
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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.ClrProfiler.Integrations;
13+
using Datadog.Trace.Configuration;
14+
15+
namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.Wcf
16+
{
17+
/// <summary>
18+
/// System.ServiceModel.Dispatcher.AsyncMethodInvoker calltarget instrumentation
19+
/// </summary>
20+
[InstrumentMethod(
21+
AssemblyName = "System.ServiceModel",
22+
TypeName = "System.ServiceModel.Dispatcher.AsyncMethodInvoker",
23+
MethodName = "InvokeBegin",
24+
ReturnTypeName = ClrNames.IAsyncResult,
25+
ParameterTypeNames = new[] { ClrNames.Object, "System.Object[]", ClrNames.AsyncCallback, ClrNames.Object },
26+
MinimumVersion = "4.0.0",
27+
MaximumVersion = "4.*.*",
28+
IntegrationName = WcfCommon.IntegrationName)]
29+
[Browsable(false)]
30+
[EditorBrowsable(EditorBrowsableState.Never)]
31+
public class AsyncMethodInvoker_InvokeBegin_Integration
32+
{
33+
/// <summary>
34+
/// OnMethodBegin callback
35+
/// </summary>
36+
/// <typeparam name="TTarget">Type of the target</typeparam>
37+
/// <param name="instance">Instance value, aka `this` of the instrumented method.</param>
38+
/// <param name="instanceArg">RequestContext instance</param>
39+
/// <param name="inputs">Input arguments</param>
40+
/// <param name="callback">Callback argument</param>
41+
/// <param name="state">State argument</param>
42+
/// <returns>Calltarget state value</returns>
43+
public static CallTargetState OnMethodBegin<TTarget>(TTarget instance, object instanceArg, object[] inputs, AsyncCallback callback, object state)
44+
{
45+
// TODO Just use the OperationContext.Current object to get the span information
46+
// context.IncomingMessageHeaders contains:
47+
// - Action
48+
// - To
49+
//
50+
// context.IncomingMessageProperties contains:
51+
// - ["httpRequest"] key to find distributed tracing headers
52+
if (!Tracer.Instance.Settings.IsIntegrationEnabled(WcfCommon.IntegrationId) || !Tracer.Instance.Settings.DelayWcfInstrumentationEnabled || WcfCommon.GetCurrentOperationContext is null)
53+
{
54+
return CallTargetState.GetDefault();
55+
}
56+
57+
var requestContext = WcfCommon.GetCurrentOperationContext()?.GetProperty<object>("RequestContext").GetValueOrDefault();
58+
return new CallTargetState(WcfIntegration.CreateScope(requestContext));
59+
}
60+
}
61+
}
62+
#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

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Wcf/ChannelHandlerIntegration.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ public class ChannelHandlerIntegration
4242
/// <returns>Calltarget state value</returns>
4343
public static CallTargetState OnMethodBegin<TTarget, TRequestContext, TOperationContext>(TTarget instance, TRequestContext request, TOperationContext currentOperationContext)
4444
{
45+
if (Tracer.Instance.Settings.DelayWcfInstrumentationEnabled)
46+
{
47+
return CallTargetState.GetDefault();
48+
}
49+
4550
return new CallTargetState(WcfIntegration.CreateScope(request));
4651
}
4752

0 commit comments

Comments
 (0)