11---
22title : 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
44ms.topic : tutorial
55ms.date : 03/14/2021
66---
77
88# Collect a distributed trace
99
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
1211
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
1616[ the instrumentation tutorial] ( distributed-tracing-instrumentation-walkthroughs.md ) if you need to add new instrumentation.
1717
18- ## Collect using OpenTelemetry
18+ ## Collect traces using OpenTelemetry
1919
2020### Prerequisites
2121
@@ -31,16 +31,17 @@ dotnet new console
3131
3232Applications that target .NET 5 and later already have the necessary distributed tracing APIs included. For apps targeting older
3333.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+
3536``` dotnetcli
36- dotnet add package System.Diagnostics.DiagnosticSource --version 5.0.1
37+ dotnet add package System.Diagnostics.DiagnosticSource
3738```
3839
3940Replace the contents of the generated Program.cs with this example source:
41+
4042``` C#
4143using System ;
4244using System .Diagnostics ;
43- using System .Net .Http ;
4445using System .Threading .Tasks ;
4546
4647namespace Sample .DistributedTracing
@@ -83,23 +84,32 @@ namespace Sample.DistributedTracing
8384}
8485```
8586
86- Running the app does not log anything yet
87+ Running the app does not record any tracing information yet
88+
8789``` dotnetcli
8890> dotnet run
8991Example work done
9092```
9193
92- ### Add logging using OpenTelemetry
94+ ### Collect using OpenTelemetry
9395
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
95104[ OpenTelemetry.Exporter.Console] ( https://www.nuget.org/packages/OpenTelemetry.Exporter.Console/ ) NuGet packages.
96105
97106``` dotnetcli
98107dotnet add package OpenTelemetry
99108dotnet add package OpenTelemetry.Exporter.Console
100109```
101110
102- Update Program.cs with additional using statments:
111+ Update Program.cs with additional OpenTelemetry using statments:
112+
103113``` C#
104114using OpenTelemetry ;
105115using OpenTelemetry .Trace ;
@@ -108,15 +118,13 @@ using System.Diagnostics;
108118using System .Threading .Tasks ;
109119```
110120
111- And update Main() to create the OpenTelemetry TracerProvider:
121+ Update Main() to create the OpenTelemetry TracerProvider:
122+
112123``` C#
113124 public static async Task Main ()
114125 {
115126 using var tracerProvider = Sdk .CreateTracerProviderBuilder ()
116- .SetSampler (new AlwaysOnSampler ())
117- // Add more libraries
118127 .AddSource (" Sample.DistributedTracing" )
119- // Add more exporters
120128 .AddConsoleExporter ()
121129 .Build ();
122130
@@ -125,7 +133,8 @@ And update Main() to create the OpenTelemetry TracerProvider:
125133 }
126134```
127135
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+
129138``` dotnetcli
130139> dotnet run
131140Activity.Id: 00-35c0e68b0dac3c49be08a9d9cab32579-0b7477e11aa20d40-01
@@ -157,52 +166,71 @@ Resource associated with Activity:
157166Example work done
158167```
159168
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+
160182The 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
163185[ 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.
166188
167- ## Collect using Application Insights
189+ ## Collect traces using Application Insights
168190
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 ) .
172194
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
174196information.
175197
176198> [ !NOTE]
177199> 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
179201> specific API for adding custom distributed tracing information.
180202
203+ ## Collect traces using custom logic
181204
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.
183208
184209### Prerequisites
185210
186211- [ .NET Core 3.1 SDK] ( https://dotnet.microsoft.com/download/dotnet ) or a later version
187212
188213### Create an example application
189214
215+ First you will create an example application that has some distributed trace instrumentation but no trace data is being collected.
216+
190217``` dotnetcli
191218dotnet new console
192219```
193220
194221Applications that target .NET 5 and later already have the necessary distributed tracing APIs included. For apps targeting older
195222.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+
197225``` dotnetcli
198- dotnet add package System.Diagnostics.DiagnosticSource --version 5.0.1
226+ dotnet add package System.Diagnostics.DiagnosticSource
199227```
200228
201229Replace the contents of the generated Program.cs with this example source:
230+
202231``` C#
203232using System ;
204233using System .Diagnostics ;
205- using System .Net .Http ;
206234using System .Threading .Tasks ;
207235
208236namespace Sample .DistributedTracing
@@ -245,19 +273,23 @@ namespace Sample.DistributedTracing
245273}
246274```
247275
248- Running the app does not log anything yet
276+ Running the app does not collect any trace data yet:
277+
249278``` dotnetcli
250279> dotnet run
251280Example work done
252281```
253282
254- ### Add code to log the Activities
283+ ### Add code to observe the Activities
284+
285+ Update Main() with this code:
255286
256- Update Main() with this code that logs Activities:
257287``` C#
258288 static async Task Main (string [] args )
259289 {
260290 Activity .DefaultIdFormat = ActivityIdFormat .W3C ;
291+ Activity .ForceDefaultIdFormat = true ;
292+
261293 Console .WriteLine (" {0,-15} {1,-60} {2,-15}" , " OperationName" , " Id" , " Duration" );
262294 ActivitySource .AddActivityListener (new ActivityListener ()
263295 {
@@ -273,6 +305,7 @@ Update Main() with this code that logs Activities:
273305```
274306
275307The output now includes logging:
308+
276309``` dotnetcli
277310> dotnet run
278311 OperationName Id Duration
@@ -285,41 +318,41 @@ Stopped: SomeWork 00-bdb5faffc2fc1548b6ba49a31c4a0ae0-c447fb302059784f-01
285318Example work done
286319```
287320
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
293326[ Activity IDs] ( distributed-tracing-concepts.md#activity-ids ) for more details.
294327
295328< 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
298331Activity is associated with an ActivitySource which acts as a namespace for a set of Activities.
299332This callback is invoked once for each ActivitySource in the process. Returning true indicates
300333the 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
303336create 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 >
305338indicates 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 >
309342flag set. IsAllDataRequested can be observed by the instrumented code as a hint that a listener
310343wants 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
315348called 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.
319352
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
323356< xref:System.Diagnostics.ActivityListener.Dispose?displayProperty=nameWithType > to
324357stop the flow of callbacks. Beware that in multi-threaded code callback notifications in
325358progress could be received while Dispose() is running or even very shortly after it has
0 commit comments