22title : Add distributed tracing instrumentation - .NET
33description : A tutorial to instrument distributed traces in .NET applications
44ms.topic : tutorial
5- ms.date : 03/14/2021
5+ ms.date : 06/05/2024
66---
77
88# Adding distributed tracing instrumentation
@@ -132,7 +132,7 @@ namespace Sample.DistributedTracing
132132
133133 static async Task Main (string [] args )
134134 {
135- .. .
135+ // ...
136136 ```
137137
138138#### Best practices
@@ -163,14 +163,14 @@ Use the ActivitySource object to Start and Stop Activity objects around meaningf
163163DoSomeWork() with the code shown here:
164164
165165```csharp
166- static async Task DoSomeWork(string foo, int bar)
167- {
168- using (Activity activity = source .StartActivity (" SomeWork" ))
169- {
170- await StepOne ();
171- await StepTwo ();
172- }
173- }
166+ static async Task DoSomeWork(string foo, int bar)
167+ {
168+ using (Activity activity = source .StartActivity (" SomeWork" ))
169+ {
170+ await StepOne ();
171+ await StepTwo ();
172+ }
173+ }
174174```
175175
176176Running the app now shows the new Activity being logged :
@@ -195,27 +195,23 @@ the created Activity object after executing the block. Disposing the Activity ob
195195doesn 't need to explicitly call <xref:System.Diagnostics.Activity.Stop?displayProperty=nameWithType>.
196196That simplifies the coding pattern .
197197
198- - < xref : System .Diagnostics .ActivitySource .StartActivity % 2A ? displayProperty = nameWithType > internally determines if
199- there are any listeners recording the Activity . If there are no registered listeners or there are listeners that
200- are not interested , `StartActivity ()` will return `null ` and avoid creating the Activity object . This
201- is a performance optimization so that the code pattern can still be used in functions that are called frequently .
198+ - < xref : System .Diagnostics .ActivitySource .StartActivity % 2A ? displayProperty = nameWithType > internally determines if there are any listeners recording the Activity . If there are no registered listeners or there are listeners that are not interested , `StartActivity ()` will return `null ` and avoid creating the Activity object . This is a performance optimization so that the code pattern can still be used in functions that are called frequently .
202199
203200## Optional: Populate tags
204201
205- Activities support key -value data called Tags , commonly used to store any parameters of the work that
206- may be useful for diagnostics . Update DoSomeWork () to include them :
202+ Activities support key -value data called Tags , commonly used to store any parameters of the work that may be useful for diagnostics . Update `DoSomeWork ()` to include them :
207203
208204```csharp
209- static async Task DoSomeWork (string foo , int bar )
210- {
211- using (Activity activity = source .StartActivity (" SomeWork" ))
212- {
213- activity ? .SetTag (" foo" , foo );
214- activity ? .SetTag (" bar" , bar );
215- await StepOne ();
216- await StepTwo ();
217- }
218- }
205+ static async Task DoSomeWork (string foo , int bar )
206+ {
207+ using (Activity activity = source .StartActivity (" SomeWork" ))
208+ {
209+ activity ? .SetTag (" foo" , foo );
210+ activity ? .SetTag (" bar" , bar );
211+ await StepOne ();
212+ await StepTwo ();
213+ }
214+ }
219215```
220216
221217```dotnetcli
@@ -265,18 +261,18 @@ Events are timestamped messages that can attach an arbitrary stream of additiona
265261some events to the Activity :
266262
267263```csharp
268- static async Task DoSomeWork (string foo , int bar )
269- {
270- using (Activity activity = source .StartActivity (" SomeWork" ))
271- {
272- activity ? .SetTag (" foo" , foo );
273- activity ? .SetTag (" bar" , bar );
274- await StepOne ();
275- activity ? .AddEvent (new ActivityEvent (" Part way there" ));
276- await StepTwo ();
277- activity ? .AddEvent (new ActivityEvent (" Done now" ));
278- }
279- }
264+ static async Task DoSomeWork (string foo , int bar )
265+ {
266+ using (Activity activity = source .StartActivity (" SomeWork" ))
267+ {
268+ activity ? .SetTag (" foo" , foo );
269+ activity ? .SetTag (" bar" , bar );
270+ await StepOne ();
271+ activity ? .AddEvent (new ActivityEvent (" Part way there" ));
272+ await StepTwo ();
273+ activity ? .AddEvent (new ActivityEvent (" Done now" ));
274+ }
275+ }
280276```
281277
282278```dotnetcli
@@ -312,32 +308,28 @@ with the distributed trace.
312308
313309OpenTelemetry allows each Activity to report a
314310[Status ](https :// github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status)
315- that represents the pass / fail result of the work . .NET does not currently have a strongly typed API for this purpose but
316- there is an established convention using Tags :
311+ that represents the pass / fail result of the work . .NET has a strongly - typed API for this purpose :
317312
318- - `otel .status_code ` is the Tag name used to store `StatusCode `. Values for the StatusCode tag must be one of the
319- strings "UNSET ", " OK" , or " ERROR" , which correspond respectively to the enums `Unset `, `Ok `, and `Error ` from StatusCode .
320- - `otel .status_description ` is the Tag name used to store the optional `Description `
313+ The < xref :System .Diagnostics .ActivityStatusCode > values are represented as either , `Unset `, `Ok `, and `Error `.
321314
322315Update DoSomeWork () to set status :
323316
324317```csharp
325- static async Task DoSomeWork (string foo , int bar )
326- {
327- using (Activity activity = source .StartActivity (" SomeWork" ))
328- {
329- activity ? .SetTag (" foo" , foo );
330- activity ? .SetTag (" bar" , bar );
331- await StepOne ();
332- activity ? .AddEvent (new ActivityEvent (" Part way there" ));
333- await StepTwo ();
334- activity ? .AddEvent (new ActivityEvent (" Done now" ));
335-
336- // Pretend something went wrong
337- activity ? .SetTag (" otel.status_code" , " ERROR" );
338- activity ? .SetTag (" otel.status_description" , " Use this text give more information about the error" );
339- }
340- }
318+ static async Task DoSomeWork (string foo , int bar )
319+ {
320+ using (Activity activity = source .StartActivity (" SomeWork" ))
321+ {
322+ activity ? .SetTag (" foo" , foo );
323+ activity ? .SetTag (" bar" , bar );
324+ await StepOne ();
325+ activity ? .AddEvent (new ActivityEvent (" Part way there" ));
326+ await StepTwo ();
327+ activity ? .AddEvent (new ActivityEvent (" Done now" ));
328+
329+ // Pretend something went wrong
330+ activity ? .SetStatus (ActivityStatusCode .Error , " Use this text give more information about the error" );
331+ }
332+ }
341333```
342334
343335## Optional: Add additional Activities
@@ -351,21 +343,21 @@ verbose traces, so it's not recommended.
351343Update StepOne and StepTwo to add more tracing around these separate steps :
352344
353345```csharp
354- static async Task StepOne ()
355- {
356- using (Activity activity = source .StartActivity (" StepOne" ))
357- {
358- await Task .Delay (500 );
359- }
360- }
346+ static async Task StepOne ()
347+ {
348+ using (Activity activity = source .StartActivity (" StepOne" ))
349+ {
350+ await Task .Delay (500 );
351+ }
352+ }
361353
362- static async Task StepTwo ()
363- {
364- using (Activity activity = source .StartActivity (" StepTwo" ))
365- {
366- await Task .Delay (1000 );
367- }
368- }
354+ static async Task StepTwo ()
355+ {
356+ using (Activity activity = source .StartActivity (" StepTwo" ))
357+ {
358+ await Task .Delay (1000 );
359+ }
360+ }
369361```
370362
371363```dotnetcli
0 commit comments