1
1
---
2
2
title : Collect a distributed trace - .NET
3
- description : A tutorial to collect distributed traces in .NET applications
3
+ description : Tutorials to collect distributed traces in .NET applications using OpenTelemetry, Application Insights, or ActivityListener
4
4
ms.topic : tutorial
5
5
ms.date : 03/14/2021
6
6
---
7
7
8
8
# Collect a distributed trace
9
9
10
- ** This article applies to: ✔️** .NET Core 5.0 and later versions ** or** any .NET application using the
11
- [ DiagnosticSource NuGet package] ( https://www.nuget.org/packages/System.Diagnostics.DiagnosticSource/5.0.1 ) version 5 or later
10
+ ** This article applies to: ✔️** .NET Core 2.1 and later versions ** and** .NET Framework 4.5 and later versions
12
11
13
- .NET applications can be instrumented using the < xref:System.Diagnostics.Activity?displayProperty=nameWithType > API to produce
14
- distributed tracing telemetry. In this tutorial you will record this instrumented telemetry with different telemetry collection
15
- libraries so that it is available to diagnose application issues. See
12
+ Instrumented code can create < xref:System.Diagnostics.Activity > objects as part of a distributed trace, but the information
13
+ in these objects needs to be collected into a centralized persistant store so that the entire trace can be
14
+ reviewed later. In this tutorial you will collect the distributed trace telemetry in different ways so that it is
15
+ available to diagnose application issues when needed. See
16
16
[ the instrumentation tutorial] ( distributed-tracing-instrumentation-walkthroughs.md ) if you need to add new instrumentation.
17
17
18
- ## Collect using OpenTelemetry
18
+ ## Collect traces using OpenTelemetry
19
19
20
20
### Prerequisites
21
21
@@ -31,16 +31,17 @@ dotnet new console
31
31
32
32
Applications that target .NET 5 and later already have the necessary distributed tracing APIs included. For apps targeting older
33
33
.NET versions add the [ System.Diagnostics.DiagnosticSource NuGet package] ( https://www.nuget.org/packages/System.Diagnostics.DiagnosticSource/ )
34
- version 5.0.1 or greater.
34
+ version 5 or greater.
35
+
35
36
``` dotnetcli
36
- dotnet add package System.Diagnostics.DiagnosticSource --version 5.0.1
37
+ dotnet add package System.Diagnostics.DiagnosticSource
37
38
```
38
39
39
40
Replace the contents of the generated Program.cs with this example source:
41
+
40
42
``` C#
41
43
using System ;
42
44
using System .Diagnostics ;
43
- using System .Net .Http ;
44
45
using System .Threading .Tasks ;
45
46
46
47
namespace Sample .DistributedTracing
@@ -83,23 +84,32 @@ namespace Sample.DistributedTracing
83
84
}
84
85
```
85
86
86
- Running the app does not log anything yet
87
+ Running the app does not record any tracing information yet
88
+
87
89
``` dotnetcli
88
90
> dotnet run
89
91
Example work done
90
92
```
91
93
92
- ### Add logging using OpenTelemetry
94
+ ### Collect using OpenTelemetry
93
95
94
- Add the [ OpenTelemetry] ( https://www.nuget.org/packages/OpenTelemetry/ ) and
96
+ [ OpenTelemetry] ( https://opentelemetry.io/ ) is a vendor neutral open source project supported by the
97
+ [ Cloud Native Computing Foundation] ( https://www.cncf.io/ ) that aims to standardize generating and collecting telemetry for
98
+ cloud-native software. In this example you will collect and display distributed trace information on the console though
99
+ OpenTelemetry can be reconfigured to send it elsewhere. See the
100
+ [ OpenTelemetry getting started guide] ( https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/docs/trace/getting-started/README.md )
101
+ for more information.
102
+
103
+ Add the [ OpenTelemetry] ( https://www.nuget.org/packages/OpenTelemetry/ ) and
95
104
[ OpenTelemetry.Exporter.Console] ( https://www.nuget.org/packages/OpenTelemetry.Exporter.Console/ ) NuGet packages.
96
105
97
106
``` dotnetcli
98
107
dotnet add package OpenTelemetry
99
108
dotnet add package OpenTelemetry.Exporter.Console
100
109
```
101
110
102
- Update Program.cs with additional using statments:
111
+ Update Program.cs with additional OpenTelemetry using statments:
112
+
103
113
``` C#
104
114
using OpenTelemetry ;
105
115
using OpenTelemetry .Trace ;
@@ -108,15 +118,13 @@ using System.Diagnostics;
108
118
using System .Threading .Tasks ;
109
119
```
110
120
111
- And update Main() to create the OpenTelemetry TracerProvider:
121
+ Update Main() to create the OpenTelemetry TracerProvider:
122
+
112
123
``` C#
113
124
public static async Task Main ()
114
125
{
115
126
using var tracerProvider = Sdk .CreateTracerProviderBuilder ()
116
- .SetSampler (new AlwaysOnSampler ())
117
- // Add more libraries
118
127
.AddSource (" Sample.DistributedTracing" )
119
- // Add more exporters
120
128
.AddConsoleExporter ()
121
129
.Build ();
122
130
@@ -125,7 +133,8 @@ And update Main() to create the OpenTelemetry TracerProvider:
125
133
}
126
134
```
127
135
128
- Now the app logs distributed trace information to the console:
136
+ Now the app collects distributed trace information and displays it to the console:
137
+
129
138
``` dotnetcli
130
139
> dotnet run
131
140
Activity.Id: 00-35c0e68b0dac3c49be08a9d9cab32579-0b7477e11aa20d40-01
@@ -157,52 +166,71 @@ Resource associated with Activity:
157
166
Example work done
158
167
```
159
168
169
+ #### Sources
170
+
171
+ In the example code you invoked ` AddSource("Sample.DistributedTracing") ` so that OpenTelemetry would
172
+ capture the Activities produced by the ActivitySource that was already present in the code:
173
+
174
+ ``` csharp
175
+ static ActivitySource s_source = new ActivitySource (" Sample.DistributedTracing" );
176
+ ```
177
+
178
+ Telemetry from any ActivitySource can captured by calling AddSource() with the source's name.
179
+
180
+ #### Exporters
181
+
160
182
The console exporter is helpful for quick examples or local development but in a production deployment
161
- you will probably want to send logs to a central logging store. OpenTelemetry supports a variety
162
- of different logging destinations using different
183
+ you will probably want to send traces to a centralized store. OpenTelemetry supports a variety
184
+ of destinations using different
163
185
[ exporters] ( https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#exporter-library ) .
164
- See the [ OpenTelemetry getting started] ( https://github.com/open-telemetry/opentelemetry-dotnet#getting-started )
165
- instructions for more information on configuring OpenTelemetry.
186
+ See the [ OpenTelemetry getting started guide ] ( https://github.com/open-telemetry/opentelemetry-dotnet#getting-started )
187
+ for more information on configuring OpenTelemetry.
166
188
167
- ## Collect using Application Insights
189
+ ## Collect traces using Application Insights
168
190
169
- Distributed tracing telemetry is automatically captured after configuring the Application Insights SDK
170
- ([ .NET] ( https://docs.microsoft.com/en-us/ azure/azure-monitor/app/asp-net ) , [ .NET Core] ( https://docs.microsoft.com/en-us /azure/azure-monitor/app/asp-net-core ) )
171
- or by enabling [ code-less instrumentation] ( https://docs.microsoft.com/en-us/ azure/azure-monitor/app/codeless-overview ) .
191
+ Distributed tracing telemetry is automatically captured after configuring the Application Insights SDK
192
+ ([ ASP .NET] ( https://docs.microsoft.com/azure/azure-monitor/app/asp-net ) , [ ASP .NET Core] ( https://docs.microsoft.com/azure/azure-monitor/app/asp-net-core ) )
193
+ or by enabling [ code-less instrumentation] ( https://docs.microsoft.com/azure/azure-monitor/app/codeless-overview ) .
172
194
173
- See the [ Application Insights distributed tracing documentation] ( https://docs.microsoft.com/en-us/ azure/azure-monitor/app/distributed-tracing ) for more
195
+ See the [ Application Insights distributed tracing documentation] ( https://docs.microsoft.com/azure/azure-monitor/app/distributed-tracing ) for more
174
196
information.
175
197
176
198
> [ !NOTE]
177
199
> Currently Application Insights only supports collecting specific well-known Activity instrumentation and will ignore new user added Activities. Application
178
- > Insights offers [ TrackDependency] ( https://docs.microsoft.com/en-us/ azure/azure-monitor/app/api-custom-events-metrics#trackdependency ) as a vendor
200
+ > Insights offers [ TrackDependency] ( https://docs.microsoft.com/azure/azure-monitor/app/api-custom-events-metrics#trackdependency ) as a vendor
179
201
> specific API for adding custom distributed tracing information.
180
202
203
+ ## Collect traces using custom logic
181
204
182
- ## Collect using a custom logging implementation
205
+ Developers are free to create their own customized collection logic for Activity trace data. This example collects the
206
+ telemetry using the < xref:System.Diagnostics.ActivityListener?displayProperty=nameWithType > API provided by .NET and prints
207
+ it to the console.
183
208
184
209
### Prerequisites
185
210
186
211
- [ .NET Core 3.1 SDK] ( https://dotnet.microsoft.com/download/dotnet ) or a later version
187
212
188
213
### Create an example application
189
214
215
+ First you will create an example application that has some distributed trace instrumentation but no trace data is being collected.
216
+
190
217
``` dotnetcli
191
218
dotnet new console
192
219
```
193
220
194
221
Applications that target .NET 5 and later already have the necessary distributed tracing APIs included. For apps targeting older
195
222
.NET versions add the [ System.Diagnostics.DiagnosticSource NuGet package] ( https://www.nuget.org/packages/System.Diagnostics.DiagnosticSource/ )
196
- version 5.0.1 or greater.
223
+ version 5 or greater.
224
+
197
225
``` dotnetcli
198
- dotnet add package System.Diagnostics.DiagnosticSource --version 5.0.1
226
+ dotnet add package System.Diagnostics.DiagnosticSource
199
227
```
200
228
201
229
Replace the contents of the generated Program.cs with this example source:
230
+
202
231
``` C#
203
232
using System ;
204
233
using System .Diagnostics ;
205
- using System .Net .Http ;
206
234
using System .Threading .Tasks ;
207
235
208
236
namespace Sample .DistributedTracing
@@ -245,19 +273,23 @@ namespace Sample.DistributedTracing
245
273
}
246
274
```
247
275
248
- Running the app does not log anything yet
276
+ Running the app does not collect any trace data yet:
277
+
249
278
``` dotnetcli
250
279
> dotnet run
251
280
Example work done
252
281
```
253
282
254
- ### Add code to log the Activities
283
+ ### Add code to observe the Activities
284
+
285
+ Update Main() with this code:
255
286
256
- Update Main() with this code that logs Activities:
257
287
``` C#
258
288
static async Task Main (string [] args )
259
289
{
260
290
Activity .DefaultIdFormat = ActivityIdFormat .W3C ;
291
+ Activity .ForceDefaultIdFormat = true ;
292
+
261
293
Console .WriteLine (" {0,-15} {1,-60} {2,-15}" , " OperationName" , " Id" , " Duration" );
262
294
ActivitySource .AddActivityListener (new ActivityListener ()
263
295
{
@@ -273,6 +305,7 @@ Update Main() with this code that logs Activities:
273
305
```
274
306
275
307
The output now includes logging:
308
+
276
309
``` dotnetcli
277
310
> dotnet run
278
311
OperationName Id Duration
@@ -285,41 +318,41 @@ Stopped: SomeWork 00-bdb5faffc2fc1548b6ba49a31c4a0ae0-c447fb302059784f-01
285
318
Example work done
286
319
```
287
320
288
- Setting < xref:System.Diagnostics.Activity.DefaultIdFormat?displayProperty=nameWithType > is optional
289
- but helps ensure the sample produces similar output on different .NET runtime versions. .NET 5.0 uses
290
- the W3C ID format by default but earlier .NET versions default to using
291
- < xref:System.Diagnostics.ActivityIdFormat.Hierarchical?displayProperty=nameWithType > as a precaution
292
- to avoid compatibility issues with older distributed tracing systems . See
321
+ Setting < xref:System.Diagnostics.Activity.DefaultIdFormat > and
322
+ < xref:System.Diagnostics.Activity.ForceDefaultIdFormat > is optional
323
+ but helps ensure the sample produces similar output on different .NET runtime versions. .NET 5 uses
324
+ the W3C TraceContext ID format by default but earlier .NET versions default to using
325
+ < xref:System.Diagnostics.ActivityIdFormat.Hierarchical > ID format . See
293
326
[ Activity IDs] ( distributed-tracing-concepts.md#activity-ids ) for more details.
294
327
295
328
< xref:System.Diagnostics.ActivityListener?displayProperty=nameWithType > is used to receive callbacks
296
- during the lifetime of an Activity.
297
- - < xref:System.Diagnostics.ActivityListener.ShouldListenTo?displayProperty=nameWithType > - Each
329
+ during the lifetime of an Activity.
330
+ - < xref:System.Diagnostics.ActivityListener.ShouldListenTo > - Each
298
331
Activity is associated with an ActivitySource which acts as a namespace for a set of Activities.
299
332
This callback is invoked once for each ActivitySource in the process. Returning true indicates
300
333
the listener should be notified about Activities associated with this source.
301
- - < xref:System.Diagnostics.ActivityListener.Sample?displayProperty=nameWithType > - By default
302
- < xref:System.Diagnostics.ActivitySource.StartActivity?displayProperty=nameWithType > does not
334
+ - < xref:System.Diagnostics.ActivityListener.Sample > - By default
335
+ < xref:System.Diagnostics.ActivitySource.StartActivity%2A > does not
303
336
create an Activity object unless some ActivityListener indicates it should be sampled. Returning
304
- < xref:System.Diagnostics.ActivitySamplingResult.AllDataAndRecorded?displayProperty=nameWithType >
337
+ < xref:System.Diagnostics.ActivitySamplingResult.AllDataAndRecorded >
305
338
indicates that the Activity should be created,
306
- < xref:System.Diagnostics.Activity.IsAllDataRequested?displayProperty=nameWithType > should be set
307
- to true, and < xref:System.Diagnostics.Activity.ActivityTraceFlags?displayProperty=nameWithType >
308
- will have the < xref:System.Diagnostics.ActivityTraceFlags.Recorded?displayProperty=nameWithType >
339
+ < xref:System.Diagnostics.Activity.IsAllDataRequested > should be set
340
+ to true, and < xref:System.Diagnostics.Activity.ActivityTraceFlags >
341
+ will have the < xref:System.Diagnostics.ActivityTraceFlags.Recorded >
309
342
flag set. IsAllDataRequested can be observed by the instrumented code as a hint that a listener
310
343
wants to ensure that auxilliary Activity information such as Tags and Events are populated.
311
- The Recorded flag is encoded in the W3C ID and is a hint to other processes involved in the
312
- distributed trace that this trace should be logged .
313
- - < xref:System.Diagnostics.ActivityListener.ActivityStarted?displayProperty=nameWithType > and
314
- < xref:System.Diagnostics.ActivityListener.ActivityStopped?displayProperty=nameWithType > are
344
+ The Recorded flag is encoded in the W3C TraceContext ID and is a hint to other processes
345
+ involved in the distributed trace that this trace should be sampled .
346
+ - < xref:System.Diagnostics.ActivityListener.ActivityStarted > and
347
+ < xref:System.Diagnostics.ActivityListener.ActivityStopped > are
315
348
called when an Activity is started and stopped respectively. These callbacks provide an
316
- oportunity to log any relevant information about the Activity. When an Activity has just
317
- started much of the data may still be incomplete and it will be filled in before the Activity
318
- stops.
349
+ oportunity to record relevant information about the Activity or potentially to modify it.
350
+ When an Activity has just started much of the data may still be incomplete and it will
351
+ be populated before the Activity stops.
319
352
320
- Once an ActivityListener has been created and the callbacks are populated, invoking
321
- < xref:System.Diagnostics.ActivitySource.AddActivityListener?displayProperty=nameWithType >
322
- initiates invoking the callbacks. Call
353
+ Once an ActivityListener has been created and the callbacks are populated, calling
354
+ < xref:System.Diagnostics.ActivitySource.AddActivityListener(System.Diagnostics.ActivityListener) ?displayProperty=nameWithType >
355
+ initiates invoking the callbacks. Call
323
356
< xref:System.Diagnostics.ActivityListener.Dispose?displayProperty=nameWithType > to
324
357
stop the flow of callbacks. Beware that in multi-threaded code callback notifications in
325
358
progress could be received while Dispose() is running or even very shortly after it has
0 commit comments