Skip to content

Commit fce1cb5

Browse files
authored
Release v1.6.0 (#14)
add W3C Trace Context support (IOutgoingWebRequestTracer.InjectTracingHeaders) update samples and readme bump SDK version to 1.6.0
2 parents 3a9a426 + 055012b commit fce1cb5

File tree

8 files changed

+151
-23
lines changed

8 files changed

+151
-23
lines changed

README.md

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ missing OneAgent dependency.
4747

4848
|OneAgent SDK for .NET|Required OneAgent version|Support status|
4949
|:-----------------------|:------------------------|:-----------------------|
50+
|1.6.0 |>=1.173 |Supported |
5051
|1.5.0 |>=1.171 |Supported |
5152
|1.4.0 |>=1.167 |Supported |
5253
|1.3.0 |>=1.165 |Supported |
@@ -202,16 +203,17 @@ for details on upcoming features.
202203
A more detailed specification of the features can be found in
203204
[Dynatrace OneAgent SDK](https://github.com/Dynatrace/OneAgent-SDK).
204205

205-
|Feature |Required OneAgent SDK for .NET version|
206-
|:-------------------------------------------------|:--------------------------------------|
207-
|Trace incoming web requests |>=1.5.0 |
208-
|Trace outgoing web requests |>=1.4.0 |
209-
|Custom request attributes |>=1.4.0 |
210-
|In-process linking, `SdkState` and `IOneAgentInfo`|>=1.3.0 |
211-
|Trace messaging |>=1.2.0 |
212-
|Trace remote calls |>=1.1.0 |
213-
|Logging callback |>=1.1.0 |
214-
|Trace SQL database requests |>=1.0.0-alpha |
206+
|Feature |Required OneAgent SDK for .NET version|
207+
|:-------------------------------------------------------------------------------|:--------------------------------------|
208+
|Support for W3C Trace Context (`IOutgoingWebRequestTracer.InjectTracingHeaders`)|>=1.6.0 |
209+
|Trace incoming web requests |>=1.5.0 |
210+
|Trace outgoing web requests |>=1.4.0 |
211+
|Custom request attributes |>=1.4.0 |
212+
|In-process linking, `SdkState` and `IOneAgentInfo` |>=1.3.0 |
213+
|Trace messaging |>=1.2.0 |
214+
|Trace remote calls |>=1.1.0 |
215+
|Logging callback |>=1.1.0 |
216+
|Trace SQL database requests |>=1.0.0-alpha |
215217

216218
### Trace SQL database requests
217219

@@ -503,8 +505,9 @@ foreach (KeyValuePair<string, string> header in request.Headers)
503505

504506
await tracer.TraceAsync(async () =>
505507
{
506-
// set the Dynatrace tracing header to allow linking the request on the server for end-to-end tracing
507-
request.Headers[OneAgentSdkConstants.DYNATRACE_HTTP_HEADERNAME] = tracer.GetDynatraceStringTag();
508+
// add the Dynatrace tag or W3C Trace Context (based on your configuration) to request headers to allow
509+
// the agent in the web server to link the request together for end-to-end tracing
510+
tracer.InjectTracingHeaders((key, value) => request.Headers[key] = value);
508511

509512
MyCustomHttpResponse response = await request.ExecuteAsync();
510513

@@ -729,6 +732,7 @@ see also [Releases](https://github.com/Dynatrace/OneAgent-SDK-for-dotnet/release
729732

730733
|Version |Description |
731734
|:----------|:--------------------------------------------|
735+
|1.6.0 |Adds W3C Trace Context support (`IOutgoingWebRequestTracer.InjectTracingHeaders`)|
732736
|1.5.0 |Adds incoming web request tracing |
733737
|1.4.0 |Adds custom request attributes and outgoing web request tracing |
734738
|1.3.0 |Adds in-process linking, `ITracer.Error(Exception)`, `SdkState` and `IOneAgentInfo` |

samples/Dynatrace.OneAgent.Sdk.Sample.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Dynatrace.OneAgent.Sdk" Version="1.5.0" />
10+
<PackageReference Include="Dynatrace.OneAgent.Sdk" Version="1.6.0" />
1111
</ItemGroup>
1212

1313
</Project>

samples/WebRequestTracerSamples.cs

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ public static void OutgoingWebRequest()
4242
// start tracer and send request
4343
tracer.Trace(() =>
4444
{
45-
// set the Dynatrace tracing header to allow linking the request on the server
46-
request.Headers[OneAgentSdkConstants.DYNATRACE_HTTP_HEADERNAME] = tracer.GetDynatraceStringTag();
45+
// add the Dynatrace tag or W3C Trace Context (based on your configuration) to request headers to allow
46+
// the agent in the web server to link the request together for end-to-end tracing
47+
tracer.InjectTracingHeaders((key, value) => request.Headers[key] = value); // Option 1: passing a stateful lambda, directly accessing 'request.Headers'
4748

4849
MyCustomHttpResponse response = request.Execute();
4950

@@ -75,8 +76,9 @@ public static async Task OutgoingWebRequestAsync()
7576
// start tracer and send request
7677
await tracer.TraceAsync(async () =>
7778
{
78-
// set the Dynatrace tracing header to allow linking the request on the server
79-
request.Headers[OneAgentSdkConstants.DYNATRACE_HTTP_HEADERNAME] = tracer.GetDynatraceStringTag();
79+
// add the Dynatrace tag or W3C Trace Context (based on your configuration) to request headers to allow
80+
// the agent in the web server to link the request together for end-to-end tracing
81+
tracer.InjectTracingHeaders((key, value, carrier) => carrier[key] = value, request.Headers); // Option 2: passing a stateless implementation, which gets 'request.Headers' passed as 'carrier'
8082

8183
MyCustomHttpResponse response = await request.ExecuteAsync();
8284

@@ -89,7 +91,7 @@ await tracer.TraceAsync(async () =>
8991
});
9092
}
9193

92-
private static MyCustomHttpResponse HandleIncomingWebRequest(MyCustomHttpRequest request)
94+
private static MyCustomHttpResponse HandleIncomingWebRequest(MyCustomHttpRequest request, bool sendOutgoingRequest = false)
9395
{
9496
// create web application info object describing our web service
9597
IWebApplicationInfo webAppInfo = SampleApplication.OneAgentSdk
@@ -113,6 +115,19 @@ private static MyCustomHttpResponse HandleIncomingWebRequest(MyCustomHttpRequest
113115
// start tracer
114116
return tracer.Trace(() =>
115117
{
118+
// send a nested outgoing request for demonstration
119+
if (sendOutgoingRequest)
120+
{
121+
MyCustomHttpRequest outgoingRequest = new MyCustomHttpRequest("https://www.example.com:8081/api/auditlog", "POST");
122+
IOutgoingWebRequestTracer outgoingTracer = SampleApplication.OneAgentSdk.TraceOutgoingWebRequest(outgoingRequest.Url, outgoingRequest.Method);
123+
outgoingTracer.Trace(() =>
124+
{
125+
outgoingTracer.InjectTracingHeaders((name, value) => outgoingRequest.Headers[name] = value);
126+
MyCustomHttpResponse incomingResponse = outgoingRequest.Execute();
127+
outgoingTracer.SetStatusCode(incomingResponse.StatusCode);
128+
});
129+
}
130+
116131
var response = new MyCustomHttpResponse();
117132

118133
// handle request and build response ...
@@ -133,6 +148,17 @@ public static void IncomingWebRequest()
133148
HandleIncomingWebRequest(sampleRequest);
134149
}
135150

151+
public static void LinkedIncomingOutgoingWebRequestWithTraceContext()
152+
{
153+
MyCustomHttpRequest sampleRequest = CreateSampleWebRequest();
154+
155+
// simulate incoming W3C Trace Context (sample taken from W3C spec)
156+
sampleRequest.Headers["traceparent"] = "00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01";
157+
sampleRequest.Headers["tracestate"] = "rojo=00f067aa0ba902b7,congo=t61rcWkgMzE";
158+
159+
HandleIncomingWebRequest(sampleRequest, sendOutgoingRequest: true);
160+
}
161+
136162
public static void LinkedOutgoingIncomingWebRequest()
137163
{
138164
var request = new MyCustomHttpRequest("https://www.example.com:8080/api/auth/user?group=42&location=Linz", "GET");
@@ -150,8 +176,9 @@ public static void LinkedOutgoingIncomingWebRequest()
150176
// start tracer and send request
151177
tracer.Trace(() =>
152178
{
153-
// set the Dynatrace tracing header to allow linking the request on the server
154-
request.Headers[OneAgentSdkConstants.DYNATRACE_HTTP_HEADERNAME] = tracer.GetDynatraceStringTag();
179+
// add the Dynatrace tag or W3C Trace Context (based on your configuration) to request headers to allow
180+
// the agent in the web server to link the request together for end-to-end tracing
181+
tracer.InjectTracingHeaders((key, value) => request.Headers[key] = value); // Option 1: passing a stateful lambda, directly accessing 'request.Headers'
155182

156183
MyCustomHttpResponse response = null;
157184

@@ -172,6 +199,46 @@ public static void LinkedOutgoingIncomingWebRequest()
172199
});
173200
}
174201

202+
public static void LinkedOutgoingIncomingOutgoingWebRequest()
203+
{
204+
MyCustomHttpRequest request = new MyCustomHttpRequest("https://www.example.com:8080/api/auth/user?group=42&location=Linz", "GET");
205+
request.Headers["Accept"] = "application/json; q=1.0, application/xml; q=0.8";
206+
request.Headers["Accept-Charset"] = "utf-8";
207+
request.Headers["Cache-Control"] = "no-cache,no-store,must-revalidate";
208+
209+
IOutgoingWebRequestTracer tracer = SampleApplication.OneAgentSdk.TraceOutgoingWebRequest(request.Url, request.Method);
210+
211+
foreach (KeyValuePair<string, string> header in request.Headers)
212+
{
213+
tracer.AddRequestHeader(header.Key, header.Value);
214+
}
215+
216+
// start tracer and send request
217+
tracer.Trace(() =>
218+
{
219+
// add the Dynatrace tag or W3C Trace Context (based on your configuration) to request headers to allow
220+
// the agent in the web server to link the request together for end-to-end tracing
221+
tracer.InjectTracingHeaders((key, value, carrier) => carrier[key] = value, request.Headers); // Option 2: passing a stateless implementation, which gets 'request.Headers' passed as 'carrier'
222+
223+
MyCustomHttpResponse response = null;
224+
225+
// represents server side processing
226+
Thread server = new Thread(() =>
227+
{
228+
response = HandleIncomingWebRequest(request, sendOutgoingRequest: true);
229+
});
230+
server.Start();
231+
server.Join(); // sync request, wait for result
232+
233+
tracer.SetStatusCode(response.StatusCode);
234+
235+
foreach (KeyValuePair<string, string> header in response.Headers)
236+
{
237+
tracer.AddResponseHeader(header.Key, header.Value);
238+
}
239+
});
240+
}
241+
175242
#region Helper classes for demonstration
176243

177244
private static MyCustomHttpRequest CreateSampleWebRequest()

src/Api/IOneAgentSdk.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public interface IOneAgentSdk
6161
/// <param name="serviceName">name of the remote service</param>
6262
/// <param name="serviceEndpoint">logical deployment endpoint on the server side In case of a clustered/load balanced service, the serviceEndpoint represents the common logical endpoint (e.g. registry://staging-environment/myservices/serviceA) where as the @channelEndpoint represents the actual communication endpoint. As such a single serviceEndpoint can have many channelEndpoints.</param>
6363
/// <param name="channelType">communication protocol used by remote call</param>
64-
/// <param name="channelEndpoint">this represents the communication endpoint for the remote service. This information allows Dynatrace to tie the database requests to a specific process or cloud service. It is optional.
64+
/// <param name="channelEndpoint">this represents the communication endpoint for the remote service. It is optional.
6565
/// for TCP/IP: host name/IP of the server-side (can include port)
6666
/// for UNIX domain sockets: path of domain socket file
6767
/// for named pipes: name of pipe

src/Api/IOutgoingWebRequestTracer.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
// limitations under the License.
1515
//
1616

17+
using System;
18+
1719
namespace Dynatrace.OneAgent.Sdk.Api
1820
{
1921
/// <summary>
@@ -47,5 +49,52 @@ public interface IOutgoingWebRequestTracer : ITracer, IOutgoingTaggable
4749
/// </summary>
4850
/// <param name="statusCode">HTTP status code returned by server</param>
4951
void SetStatusCode(int statusCode);
52+
53+
/// <summary>
54+
/// <para>Sets HTTP request headers required for linking requests end-to-end.</para>
55+
/// <para>
56+
/// Based on your configuration, this method will add the 'X-dynaTrace' header and/or the W3C Trace Context headers ('traceparent' and 'tracestate').<br/>
57+
/// Therefore it is no longer necessary to manually add the Dynatrace tag and thus <see cref="IOutgoingTaggable.GetDynatraceStringTag"/>
58+
/// must not be used together with this method.
59+
/// </para>
60+
/// <para>This method can only be called on an active tracer (i.e., between start and end).</para>
61+
///
62+
/// <para>Example usage:</para>
63+
/// <example><code>
64+
/// var requestHeaders = new Dictionary&lt;string, string>();
65+
/// outgoingWebRequestTracer.InjectTracingHeaders((name, value) => requestHeaders[name] = value);
66+
/// </code></example>
67+
/// </summary>
68+
///
69+
/// <param name="headerSetter">
70+
/// <para>An Action&lt;string, string> that takes the parameters (name, value) and sets the respective headers on the HTTP request.<br/>
71+
/// If a header with this name already exists, the value is overwritten.</para>
72+
/// <para>First parameter (arg1) = name: a valid HTTP header name, never null or empty<br/>
73+
/// Second parameter (arg2) = value: the header value to be set, never null</para>
74+
/// </param>
75+
void InjectTracingHeaders(Action<string, string> headerSetter);
76+
77+
/// <summary>
78+
/// <para>Same as <see cref="InjectTracingHeaders(Action{string, string})"/> but the (nullable) parameter <paramref name="carrier"/>
79+
/// provided to this method is passed along to <paramref name="headerSetter"/>.</para>
80+
///
81+
/// <para>Example usage:</para>
82+
/// <example><code>
83+
/// var requestHeaders = new Dictionary&lt;string, string>();
84+
/// outgoingWebRequestTracer.InjectTracingHeaders((name, value, carrier) => carrier[name] = value, requestHeaders);
85+
/// </code></example>
86+
/// </summary>
87+
///
88+
/// <typeparam name="TCarrier"></typeparam>
89+
/// <param name="headerSetter">
90+
/// <para>An Action&lt;string, string> that takes the parameters (name, value) and sets the respective headers on the HTTP request.<br/>
91+
/// If a header with this name already exists, the value is overwritten.</para>
92+
/// First parameter (arg1) = name: a valid HTTP header name, never null or empty<br/>
93+
/// Second parameter (arg2) = value: the header value to be set, never null<br/>
94+
/// Third parameter (arg3) = carrier: the header carrier (i.e., the web request object or its map of headers),
95+
/// as passed to <see cref="InjectTracingHeaders{TCarrier}(Action{string, string, TCarrier}, TCarrier)"/> (could be null therefore)
96+
/// </param>
97+
/// <param name="carrier">the (nullable) header carrier object passed along to <paramref name="headerSetter"/></param>
98+
void InjectTracingHeaders<TCarrier>(Action<string, string, TCarrier> headerSetter, TCarrier carrier);
5099
}
51100
}

src/DummyImpl/DummyOutgoingWebRequestTracer.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,9 @@ public void AddRequestHeader(string name, string value) { }
5959
public void AddResponseHeader(string name, string value) { }
6060

6161
public void SetStatusCode(int statusCode) { }
62+
63+
public void InjectTracingHeaders(Action<string, string> headerSetter) { }
64+
65+
public void InjectTracingHeaders<TCarrier>(Action<string, string, TCarrier> headerSetter, TCarrier carrier) { }
6266
}
6367
}

src/Dynatrace.OneAgent.Sdk.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
<PropertyGroup>
44
<TargetFramework>netstandard1.0</TargetFramework>
5-
<Version>1.5.0</Version>
5+
<Version>1.6.0</Version>
66
<Authors>Dynatrace</Authors>
77
<Product>Dynatrace OneAgent SDK for .NET</Product>
88
<Description>This SDK allows Dynatrace customers to instrument .NET applications. This is useful to enhance the visibility for proprietary frameworks or custom frameworks not directly supported by Dynatrace OneAgent out-of-the-box.
99

10-
Requires Dynatrace OneAgent version 1.171 or newer installed.
10+
Requires Dynatrace OneAgent version 1.173 or newer installed.
1111

1212
For further information (requirements, features, release notes) and samples see our readme on Github:
1313
https://github.com/Dynatrace/OneAgent-SDK-for-dotnet</Description>

test/DummyOutgoingWebRequestTracerTest.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ protected override void ExecuteTracerSpecificCalls(IOutgoingWebRequestTracer tra
3434
tracer.AddRequestHeader(null, null);
3535
tracer.AddResponseHeader("", "");
3636
tracer.AddResponseHeader(null, null);
37+
tracer.InjectTracingHeaders(null);
38+
tracer.InjectTracingHeaders((k, v) => { _ = k.Length + v.Length; });
39+
tracer.InjectTracingHeaders(null, (object)null);
40+
tracer.InjectTracingHeaders((k, v, c) => { _ = k.Length + v.Length; }, (object)null);
3741
}
3842

3943
[Fact]

0 commit comments

Comments
 (0)