Skip to content

Commit b5bcddc

Browse files
committed
Applying review feedback
1 parent 2ffd9de commit b5bcddc

File tree

4 files changed

+227
-160
lines changed

4 files changed

+227
-160
lines changed

docs/core/diagnostics/distributed-tracing-collection-walkthroughs.md

Lines changed: 92 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
---
22
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
44
ms.topic: tutorial
55
ms.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

3232
Applications 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

3940
Replace the contents of the generated Program.cs with this example source:
41+
4042
```C#
4143
using System;
4244
using System.Diagnostics;
43-
using System.Net.Http;
4445
using System.Threading.Tasks;
4546

4647
namespace 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
8991
Example 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
98107
dotnet add package OpenTelemetry
99108
dotnet 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#
104114
using OpenTelemetry;
105115
using OpenTelemetry.Trace;
@@ -108,15 +118,13 @@ using System.Diagnostics;
108118
using 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
131140
Activity.Id: 00-35c0e68b0dac3c49be08a9d9cab32579-0b7477e11aa20d40-01
@@ -157,52 +166,71 @@ Resource associated with Activity:
157166
Example 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+
160182
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
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
174196
information.
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
191218
dotnet new console
192219
```
193220

194221
Applications 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

201229
Replace the contents of the generated Program.cs with this example source:
230+
202231
```C#
203232
using System;
204233
using System.Diagnostics;
205-
using System.Net.Http;
206234
using System.Threading.Tasks;
207235

208236
namespace 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
251280
Example 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

275307
The output now includes logging:
308+
276309
```dotnetcli
277310
> dotnet run
278311
OperationName Id Duration
@@ -285,41 +318,41 @@ Stopped: SomeWork 00-bdb5faffc2fc1548b6ba49a31c4a0ae0-c447fb302059784f-01
285318
Example 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
298331
Activity is associated with an ActivitySource which acts as a namespace for a set of Activities.
299332
This callback is invoked once for each ActivitySource in the process. Returning true indicates
300333
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
303336
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>
305338
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>
309342
flag set. IsAllDataRequested can be observed by the instrumented code as a hint that a listener
310343
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
315348
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.
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
324357
stop the flow of callbacks. Beware that in multi-threaded code callback notifications in
325358
progress could be received while Dispose() is running or even very shortly after it has

0 commit comments

Comments
 (0)