Skip to content

Commit 3928831

Browse files
Add new instrumentation for System.ServiceModel.Dispatcher.TaskMethodInvoker and update snapshots
1 parent c50d70e commit 3928831

5 files changed

+298
-0
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// <copyright file="TaskMethodInvokerIntegration.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.TaskMethodInvoker calltarget instrumentation
19+
/// </summary>
20+
[InstrumentMethod(
21+
AssemblyName = "System.ServiceModel",
22+
TypeName = "System.ServiceModel.Dispatcher.TaskMethodInvoker",
23+
MethodName = "InvokeAsync",
24+
ReturnTypeName = "System.Threading.Tasks.Task`1<System.Tuple`2<System.Object, System.Object[]>>",
25+
ParameterTypeNames = new[] { ClrNames.Object, "System.Object[]" },
26+
MinimumVersion = "4.0.0",
27+
MaximumVersion = "4.*.*",
28+
IntegrationName = IntegrationName)]
29+
[Browsable(false)]
30+
[EditorBrowsable(EditorBrowsableState.Never)]
31+
public class TaskMethodInvokerIntegration
32+
{
33+
private const string IntegrationName = nameof(IntegrationIds.Wcf);
34+
private static readonly Func<object> _getCurrentOperationContext;
35+
36+
static TaskMethodInvokerIntegration()
37+
{
38+
var operationContextType = Type.GetType("System.ServiceModel.OperationContext, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", throwOnError: false);
39+
if (operationContextType is not null)
40+
{
41+
var property = operationContextType.GetProperty("Current", BindingFlags.Public | BindingFlags.Static);
42+
var method = property.GetGetMethod();
43+
_getCurrentOperationContext = (Func<object>)method.CreateDelegate(typeof(Func<object>));
44+
}
45+
}
46+
47+
/// <summary>
48+
/// OnMethodBegin callback
49+
/// </summary>
50+
/// <typeparam name="TTarget">Type of the target</typeparam>
51+
/// <param name="instance">Instance value, aka `this` of the instrumented method.</param>
52+
/// <param name="instanceArg">RequestContext instance</param>
53+
/// <param name="inputs">Input arguments</param>
54+
/// <returns>Calltarget state value</returns>
55+
public static CallTargetState OnMethodBegin<TTarget>(TTarget instance, object instanceArg, object[] inputs)
56+
{
57+
// TODO Just use the OperationContext.Current object to get the span information
58+
// context.IncomingMessageHeaders contains:
59+
// - Action
60+
// - To
61+
//
62+
// context.IncomingMessageProperties contains:
63+
// - ["httpRequest"] key to find distributed tracing headers
64+
if (_getCurrentOperationContext is null || !Tracer.Instance.Settings.WcfEnableNewInstrumentation)
65+
{
66+
return CallTargetState.GetDefault();
67+
}
68+
69+
var requestContext = _getCurrentOperationContext()?.GetProperty<object>("RequestContext").GetValueOrDefault();
70+
return new CallTargetState(WcfIntegration.CreateScope(requestContext));
71+
}
72+
73+
/// <summary>
74+
/// OnAsyncMethodEnd callback
75+
/// </summary>
76+
/// <typeparam name="TTarget">Type of the target</typeparam>
77+
/// <typeparam name="TResponse">Type of the response, in an async scenario will be T of Task of T</typeparam>
78+
/// <param name="instance">Instance value, aka `this` of the instrumented method.</param>
79+
/// <param name="returnValue">Return value</param>
80+
/// <param name="exception">Exception instance in case the original code threw an exception.</param>
81+
/// <param name="state">Calltarget state value</param>
82+
/// <returns>A response value, in an async scenario will be T of Task of T</returns>
83+
public static TResponse OnAsyncMethodEnd<TTarget, TResponse>(TTarget instance, TResponse returnValue, Exception exception, CallTargetState state)
84+
{
85+
state.Scope.DisposeWithException(exception);
86+
return returnValue;
87+
}
88+
}
89+
}
90+
#endif

tracer/src/Datadog.Trace/ClrProfiler/InstrumentationDefinitions.Generated.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ private static NativeCallTargetDefinition[] GetDefinitionsArray()
268268
// Wcf
269269
new("System.ServiceModel", "System.ServiceModel.Dispatcher.ChannelHandler", "HandleRequest", new[] { "System.Boolean", "System.ServiceModel.Channels.RequestContext", "System.ServiceModel.OperationContext" }, new ushort[] { }, 4, 0, 0, 4, 65535, 65535, assemblyFullName, "Datadog.Trace.ClrProfiler.AutoInstrumentation.Wcf.ChannelHandlerIntegration"),
270270
new("System.ServiceModel", "System.ServiceModel.Dispatcher.SyncMethodInvoker", "Invoke", new[] { "System.Object", "System.Object", "System.Object[]", "System.Object[]&" }, new ushort[] { 0, 1 }, 4, 0, 0, 4, 65535, 65535, assemblyFullName, "Datadog.Trace.ClrProfiler.AutoInstrumentation.Wcf.SyncMethodInvokerIntegration"),
271+
new("System.ServiceModel", "System.ServiceModel.Dispatcher.TaskMethodInvoker", "InvokeAsync", new[] { "System.Threading.Tasks.Task`1<System.Tuple`2<System.Object, System.Object[]>>", "System.Object", "System.Object[]" }, new ushort[] { }, 4, 0, 0, 4, 65535, 65535, assemblyFullName, "Datadog.Trace.ClrProfiler.AutoInstrumentation.Wcf.TaskMethodInvokerIntegration"),
271272

272273
// WebRequest
273274
new("System", "System.Net.HttpWebRequest", "BeginGetRequestStream", new[] { "System.IAsyncResult", "System.AsyncCallback", "System.Object" }, new ushort[] { }, 4, 0, 0, 4, 65535, 65535, assemblyFullName, "Datadog.Trace.ClrProfiler.AutoInstrumentation.Http.WebRequest.HttpWebRequest_BeginGetRequestStream_Integration"),

tracer/test/snapshots/WcfTests.__binding=BasicHttpBinding_enableCallTarget=True_enableNewWcfInstrumentation=True.verified.txt

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,77 @@
7070
_dd.tracer_kr: 1.0,
7171
_dd.top_level: 1.0
7272
}
73+
},
74+
{
75+
TraceId: Id_10,
76+
SpanId: Id_11,
77+
Name: wcf.request,
78+
Resource: WcfSample/ICalculator/ServerTaskAdd,
79+
Service: Samples.Wcf,
80+
Type: web,
81+
ParentId: Id_12,
82+
Tags: {
83+
env: integration_tests,
84+
http.method: POST,
85+
http.request.headers.host: localhost:00000,
86+
http.url: http://localhost:00000/WcfSample/CalculatorService,
87+
language: dotnet,
88+
runtime-id: Guid_1,
89+
span.kind: server,
90+
version: 1.0.0
91+
},
92+
Metrics: {
93+
_sampling_priority_v1: 1.0,
94+
_dd.tracer_kr: 1.0,
95+
_dd.top_level: 1.0
96+
}
97+
},
98+
{
99+
TraceId: Id_13,
100+
SpanId: Id_14,
101+
Name: wcf.request,
102+
Resource: WcfSample/ICalculator/ServerTaskAdd,
103+
Service: Samples.Wcf,
104+
Type: web,
105+
ParentId: Id_15,
106+
Tags: {
107+
env: integration_tests,
108+
http.method: POST,
109+
http.request.headers.host: localhost:00000,
110+
http.url: http://localhost:00000/WcfSample/CalculatorService,
111+
language: dotnet,
112+
runtime-id: Guid_1,
113+
span.kind: server,
114+
version: 1.0.0
115+
},
116+
Metrics: {
117+
_sampling_priority_v1: 1.0,
118+
_dd.tracer_kr: 1.0,
119+
_dd.top_level: 1.0
120+
}
121+
},
122+
{
123+
TraceId: Id_16,
124+
SpanId: Id_17,
125+
Name: wcf.request,
126+
Resource: WcfSample/ICalculator/ServerTaskAdd,
127+
Service: Samples.Wcf,
128+
Type: web,
129+
ParentId: Id_18,
130+
Tags: {
131+
env: integration_tests,
132+
http.method: POST,
133+
http.request.headers.host: localhost:00000,
134+
http.url: http://localhost:00000/WcfSample/CalculatorService,
135+
language: dotnet,
136+
runtime-id: Guid_1,
137+
span.kind: server,
138+
version: 1.0.0
139+
},
140+
Metrics: {
141+
_sampling_priority_v1: 1.0,
142+
_dd.tracer_kr: 1.0,
143+
_dd.top_level: 1.0
144+
}
73145
}
74146
]

tracer/test/snapshots/WcfTests.__binding=NetTcpBinding_enableCallTarget=True_enableNewWcfInstrumentation=True.verified.txt

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,68 @@
6161
_dd.tracer_kr: 1.0,
6262
_dd.top_level: 1.0
6363
}
64+
},
65+
{
66+
TraceId: Id_7,
67+
SpanId: Id_8,
68+
Name: wcf.request,
69+
Resource: WcfSample/ICalculator/ServerTaskAdd,
70+
Service: Samples.Wcf,
71+
Type: web,
72+
Tags: {
73+
env: integration_tests,
74+
http.url: net.tcp://localhost:00000/WcfSample/CalculatorService,
75+
language: dotnet,
76+
runtime-id: Guid_1,
77+
span.kind: server,
78+
version: 1.0.0
79+
},
80+
Metrics: {
81+
_sampling_priority_v1: 1.0,
82+
_dd.tracer_kr: 1.0,
83+
_dd.top_level: 1.0
84+
}
85+
},
86+
{
87+
TraceId: Id_9,
88+
SpanId: Id_10,
89+
Name: wcf.request,
90+
Resource: WcfSample/ICalculator/ServerTaskAdd,
91+
Service: Samples.Wcf,
92+
Type: web,
93+
Tags: {
94+
env: integration_tests,
95+
http.url: net.tcp://localhost:00000/WcfSample/CalculatorService,
96+
language: dotnet,
97+
runtime-id: Guid_1,
98+
span.kind: server,
99+
version: 1.0.0
100+
},
101+
Metrics: {
102+
_sampling_priority_v1: 1.0,
103+
_dd.tracer_kr: 1.0,
104+
_dd.top_level: 1.0
105+
}
106+
},
107+
{
108+
TraceId: Id_11,
109+
SpanId: Id_12,
110+
Name: wcf.request,
111+
Resource: WcfSample/ICalculator/ServerTaskAdd,
112+
Service: Samples.Wcf,
113+
Type: web,
114+
Tags: {
115+
env: integration_tests,
116+
http.url: net.tcp://localhost:00000/WcfSample/CalculatorService,
117+
language: dotnet,
118+
runtime-id: Guid_1,
119+
span.kind: server,
120+
version: 1.0.0
121+
},
122+
Metrics: {
123+
_sampling_priority_v1: 1.0,
124+
_dd.tracer_kr: 1.0,
125+
_dd.top_level: 1.0
126+
}
64127
}
65128
]

tracer/test/snapshots/WcfTests.__binding=WSHttpBinding_enableCallTarget=True_enableNewWcfInstrumentation=True.verified.txt

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,77 @@
7070
_dd.tracer_kr: 1.0,
7171
_dd.top_level: 1.0
7272
}
73+
},
74+
{
75+
TraceId: Id_10,
76+
SpanId: Id_11,
77+
Name: wcf.request,
78+
Resource: WcfSample/ICalculator/ServerTaskAdd,
79+
Service: Samples.Wcf,
80+
Type: web,
81+
ParentId: Id_12,
82+
Tags: {
83+
env: integration_tests,
84+
http.method: POST,
85+
http.request.headers.host: localhost:00000,
86+
http.url: http://localhost:00000/WcfSample/CalculatorService,
87+
language: dotnet,
88+
runtime-id: Guid_1,
89+
span.kind: server,
90+
version: 1.0.0
91+
},
92+
Metrics: {
93+
_sampling_priority_v1: 1.0,
94+
_dd.tracer_kr: 1.0,
95+
_dd.top_level: 1.0
96+
}
97+
},
98+
{
99+
TraceId: Id_13,
100+
SpanId: Id_14,
101+
Name: wcf.request,
102+
Resource: WcfSample/ICalculator/ServerTaskAdd,
103+
Service: Samples.Wcf,
104+
Type: web,
105+
ParentId: Id_15,
106+
Tags: {
107+
env: integration_tests,
108+
http.method: POST,
109+
http.request.headers.host: localhost:00000,
110+
http.url: http://localhost:00000/WcfSample/CalculatorService,
111+
language: dotnet,
112+
runtime-id: Guid_1,
113+
span.kind: server,
114+
version: 1.0.0
115+
},
116+
Metrics: {
117+
_sampling_priority_v1: 1.0,
118+
_dd.tracer_kr: 1.0,
119+
_dd.top_level: 1.0
120+
}
121+
},
122+
{
123+
TraceId: Id_16,
124+
SpanId: Id_17,
125+
Name: wcf.request,
126+
Resource: WcfSample/ICalculator/ServerTaskAdd,
127+
Service: Samples.Wcf,
128+
Type: web,
129+
ParentId: Id_18,
130+
Tags: {
131+
env: integration_tests,
132+
http.method: POST,
133+
http.request.headers.host: localhost:00000,
134+
http.url: http://localhost:00000/WcfSample/CalculatorService,
135+
language: dotnet,
136+
runtime-id: Guid_1,
137+
span.kind: server,
138+
version: 1.0.0
139+
},
140+
Metrics: {
141+
_sampling_priority_v1: 1.0,
142+
_dd.tracer_kr: 1.0,
143+
_dd.top_level: 1.0
144+
}
73145
}
74146
]

0 commit comments

Comments
 (0)