### Full Program.cs example using MeterListener Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/metrics-collection Complete example that creates a Meter and Counter, subscribes to instruments via MeterListener, and prints measurements. The listener is started and the app simulates hat sales until a key is pressed. ```csharp using System.Diagnostics.Metrics; class Program { static Meter s_meter = new("HatCo.HatStore", "1.0.0"); static Counter s_hatsSold = s_meter.CreateCounter( name: "hats-sold", unit: "Hats", description: "The number of hats sold in our store"); static void Main(string[] args) { using MeterListener meterListener = new(); meterListener.InstrumentPublished = (instrument, listener) => { if (instrument.Meter.Name is "HatCo.HatStore") { listener.EnableMeasurementEvents(instrument); } }; meterListener.SetMeasurementEventCallback(OnMeasurementRecorded); // Start the meterListener, enabling InstrumentPublished callbacks. meterListener.Start(); var rand = Random.Shared; Console.WriteLine("Press any key to exit"); while (!Console.KeyAvailable) { //// Simulate hat selling transactions. Thread.Sleep(rand.Next(100, 2500)); s_hatsSold.Add(rand.Next(0, 1000)); } } static void OnMeasurementRecorded( Instrument instrument, T measurement, ReadOnlySpan> tags, object? state) { Console.WriteLine($"{instrument.Name} recorded measurement {measurement}"); } } ``` -------------------------------- ### Install perfcollect prerequisites Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/trace-perfcollect-lttng Runs the install command with sudo to install the required tracing libraries: perf and LTTng. This is the final preparation step. ```bash sudo ./perfcollect install ``` -------------------------------- ### dotnet-stack ps example output Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-stack Example output from running dotnet-stack ps after starting a long-running app with 'dotnet run --configuration Release'. The command-line arguments are shown in dotnet-stack version 6.0.320703 and later. ```text > dotnet-stack ps 21932 dotnet C:\Program Files\dotnet\dotnet.exe run --configuration Release 36656 dotnet C:\Program Files\dotnet\dotnet.exe ``` -------------------------------- ### dotnet-sos install synopsis Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-sos Shows the syntax for the install command, including the optional --architecture option. ```text dotnet-sos install [--architecture ] ``` -------------------------------- ### Install SOS extension Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/debug-stackoverflow Installs the SOS extension using the dotnet-sos command. ```bash dotnet-sos install ``` -------------------------------- ### Install dotnet-monitor as a global tool Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-monitor Use the dotnet tool install command to install the latest release version of the dotnet-monitor NuGet package as a global tool. ```bash dotnet tool install --global dotnet-monitor ``` -------------------------------- ### dotnet-debugger-extensions install synopsis Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-debugger-extensions Shows the syntax for the install subcommand, which installs the .NET debugger extensions locally. The --architecture option specifies the processor architecture of the extension binaries. ```bash dotnet-debugger-extensions install [--architecture ] ``` -------------------------------- ### Install LLDB on Fedora 29 and later Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/lldb-linux Install lldb and python2-lldb using dnf on Fedora. ```bash sudo dnf install lldb python2-lldb ``` -------------------------------- ### Install LLDB on Ubuntu 20.04 and later Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/lldb-linux Update package lists and install lldb using apt-get on Ubuntu. ```bash sudo apt-get update sudo apt-get install lldb ``` -------------------------------- ### Install dotnet-counters Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/debug-highcpu Install the latest version of dotnet-counters globally using the .NET tool command. ```bash dotnet tool install --global dotnet-counters ``` -------------------------------- ### Install dotnet-trace as a global tool Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-trace Use this command to install the latest release version of the dotnet-trace NuGet package as a global tool. ```bash dotnet tool install --global dotnet-trace ``` -------------------------------- ### Run the sample app with dotnet run Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/debug-threadpool-starvation Starts the sample ASP.NET Core web app using the .NET SDK. The output shows the app listening on https://localhost:5001 and http://localhost:5000, and indicates the hosting environment and content root path. ```bash E:\demo\DiagnosticScenarios>dotnet run Using launch settings from E:\demo\DiagnosticScenarios\Properties\launchSettings.json... info: Microsoft.Hosting.Lifetime[14] Now listening on: https://localhost:5001 info: Microsoft.Hosting.Lifetime[14] Now listening on: http://localhost:5000 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0] Hosting environment: Development info: Microsoft.Hosting.Lifetime[0] Content root path: E:\demo\DiagnosticScenarios ``` -------------------------------- ### dotnet-gcdump ps example output Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-gcdump Example output from running 'dotnet-gcdump ps' after starting an app with 'dotnet run --configuration Release'. The command-line arguments are shown with dotnet-gcdump 6.0.320703 and later. ```text > dotnet-gcdump ps 21932 dotnet C:\Program Files\dotnet\dotnet.exe run --configuration Release 36656 dotnet C:\Program Files\dotnet\dotnet.exe ``` -------------------------------- ### Run sample application Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/debug-highcpu Run the sample application from the project root directory to observe high CPU usage. ```bash dotnet run ``` -------------------------------- ### dotnet-trace ps example output Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-trace Example output from running dotnet-trace ps after starting a long-running app with 'dotnet run --configuration Release'. The output lists process IDs, process names, executable paths, and command-line arguments (if available) for dotnet-trace 6.0.320703 and later. ```bash > dotnet-trace ps 21932 dotnet C:\Program Files\dotnet\dotnet.exe run --configuration Release 36656 dotnet C:\Program Files\dotnet\dotnet.exe ``` -------------------------------- ### ApplyStartupHook(string) Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/microsoft-diagnostics-netcore-client Loads the specified assembly with a StartupHook in the target process. ```APIDOC ## ApplyStartupHook(string) ### Description Loads the specified assembly with a StartupHook in the target process. ### Method ApplyStartupHook ### Parameters - **startupHookPath** (string) - Required - The path to the assembly containing the startup hook. ### Returns void ``` -------------------------------- ### Download debug symbols for runtime libraries Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-trace Downloads debug symbols for the runtime libraries at the specified path. The example uses `/usr/share/dotnet/shared/Microsoft.NETCore.App/10.0.0` as the runtime installation path. ```bash dotnet-symbol --symbols /usr/share/dotnet/shared/Microsoft.NETCore.App/10.0.0/lib*.so ``` -------------------------------- ### Run dotnet-counters with dnx Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-counters Starting with .NET 10.0.100, use dnx to run dotnet-counters without permanent installation. This command automatically downloads and runs the latest version. ```bash dnx dotnet-counters [options] ``` -------------------------------- ### Create example app with metric instrumentation Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/metrics-collection Commands to create a new console app, change to its directory, and add the System.Diagnostics.DiagnosticSource package. This is the first step in setting up the example app for metric collection. ```bash dotnet new console -o metric-instr cd metric-instr dotnet add package System.Diagnostics.DiagnosticSource ``` -------------------------------- ### Prometheus startup output showing port 9090 Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/observability-prgrja-example Example output from starting Prometheus, showing it listens on port 9090 by default. Use this port to access the Prometheus UI. ```plaintext >prometheus.exe ... ts=2023-06-16T05:29:02.789Z caller=web.go:562 level=info component=web msg="Start listening for connections" address=0.0.0.0:9090 ``` -------------------------------- ### Replace Program.cs with example source Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs Replaces the generated Program.cs with a sample that sets up OpenTelemetry and runs some simulated work. The app has no instrumentation yet. ```csharp using OpenTelemetry; using OpenTelemetry.Resources; using OpenTelemetry.Trace; using System; using System.Threading.Tasks; namespace Sample.DistributedTracing { class Program { static async Task Main(string[] args) { using var tracerProvider = Sdk.CreateTracerProviderBuilder() .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MySample")) .AddSource("Sample.DistributedTracing") .AddConsoleExporter() .Build(); await DoSomeWork("banana", 8); Console.WriteLine("Example work done"); } // All the functions below simulate doing some arbitrary work static async Task DoSomeWork(string foo, int bar) { await StepOne(); await StepTwo(); } static async Task StepOne() { await Task.Delay(500); } static async Task StepTwo() { await Task.Delay(1000); } } } ``` -------------------------------- ### Sample JSON output from dotnet-counters collect Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/event-counter-perf Example content of the diagnostics.json file produced by the collect command. It includes target process, start time, and an array of events with timestamp, provider, name, counter type, and value. ```json { "TargetProcess": "DiagnosticScenarios", "StartTime": "8/5/2020 3:02:45 PM", "Events": [ { "timestamp": "2020-08-05 15:02:47Z", "provider": "System.Runtime", "name": "CPU Usage (%)", "counterType": "Metric", "value": 0 }, { "timestamp": "2020-08-05 15:02:47Z", "provider": "Microsoft.AspNetCore.Hosting", "name": "Request Rate / 1 sec", "counterType": "Rate", "value": 0 }, { "timestamp": "2020-08-05 15:02:47Z", "provider": "Microsoft.AspNetCore.Hosting", "name": "Total Requests", "counterType": "Metric", "value": 134 }, { "timestamp": "2020-08-05 15:02:47Z", "provider": "Sample.EventCounter.Minimal", "name": "Request Processing Time (ms)", "counterType": "Metric", "value": 0 }, { "timestamp": "2020-08-05 15:02:47Z", "provider": "System.Runtime", "name": "CPU Usage (%)", "counterType": "Metric", "value": 0 }, { "timestamp": "2020-08-05 15:02:48Z", "provider": "Microsoft.AspNetCore.Hosting", "name": "Request Rate / 1 sec", "counterType": "Rate", "value": 0 }, { "timestamp": "2020-08-05 15:02:48Z", "provider": "Microsoft.AspNetCore.Hosting", "name": "Total Requests", "counterType": "Metric", "value": 134 }, { "timestamp": "2020-08-05 15:02:48Z", "provider": "Sample.EventCounter.Minimal", "name": "Request Processing Time (ms)", "counterType": "Metric", "value": 0 }, { "timestamp": "2020-08-05 15:02:48Z", "provider": "System.Runtime", "name": "CPU Usage (%)", "counterType": "Metric", "value": 0 }, { "timestamp": "2020-08-05 15:02:50Z", "provider": "Microsoft.AspNetCore.Hosting", "name": "Request Rate / 1 sec", "counterType": "Rate", "value": 0 }, { "timestamp": "2020-08-05 15:02:50Z", "provider": "Microsoft.AspNetCore.Hosting", "name": "Total Requests", "counterType": "Metric", "value": 134 }, { "timestamp": "2020-08-05 15:02:50Z", "provider": "Sample.EventCounter.Minimal", "name": "Request Processing Time (ms)", "counterType": "Metric", "value": 0 } ] } ``` -------------------------------- ### Run the app and observe output Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-collection-walkthroughs Running the app does not collect any trace data yet. The output shows 'Example work done'. ```bash > dotnet run Example work done ``` -------------------------------- ### Test custom metrics with dependency injection using MetricCollector Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/metrics-instrumentation Example test case for code components that use dependency injection and IMeterFactory. It creates a service provider, gets the HatCoMetrics instance and IMeterFactory, then uses MetricCollector to record and assert measurements. The CreateServiceProvider method sets up the service collection with AddMetrics and registers HatCoMetrics as a singleton. ```csharp public class MetricTests { [Fact] public void SaleIncrementsHatsSoldCounter() { // Arrange var services = CreateServiceProvider(); var metrics = services.GetRequiredService(); var meterFactory = services.GetRequiredService(); var collector = new MetricCollector(meterFactory, "HatCo.Store", "hatco.store.hats_sold"); // Act metrics.HatsSold(15); // Assert var measurements = collector.GetMeasurementSnapshot(); Assert.Equal(1, measurements.Count); Assert.Equal(15, measurements[0].Value); } // Setup a new service provider. This example creates the collection explicitly but you might leverage // a host or some other application setup code to do this as well. private static IServiceProvider CreateServiceProvider() { var serviceCollection = new ServiceCollection(); serviceCollection.AddMetrics(); serviceCollection.AddSingleton(); return serviceCollection.BuildServiceProvider(); } } ``` -------------------------------- ### Start perfcollect collection Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/trace-perfcollect-lttng Starts trace collection with perfcollect. The output confirms collection has started and prompts to press Ctrl+C to stop. ```bash sudo ./perfcollect collect sampleTrace ``` ```text Collection started. Press CTRL+C to stop. ``` -------------------------------- ### Launch executable with arguments and monitor working set and GC heap size Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-counters Launches my-aspnet-server.exe with command-line arguments arg1 and arg2 and monitors the working set and GC heap size from startup. The output shows the heap sizes for gen0, gen1, gen2, loh, and poh, and the working set in bytes. ```bash > dotnet-counters monitor --counters System.Runtime[dotnet.process.memory.working_set,dotnet.gc.last_collection.heap.size] -- my-aspnet-server.exe arg1 arg2 ``` ```bash Name Current Value [System.Runtime] dotnet.gc.last_collection.heap.size (By) gc.heap.generation ------------------ gen0 560 gen1 462,720 gen2 0 loh 0 poh 8,184 dotnet.process.memory.working_set (By) 48,431,104 ``` -------------------------------- ### Sample Program.cs with ActivitySource and StartActivity Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-collection-walkthroughs Replace the generated Program.cs with this example source. It defines an ActivitySource and uses StartActivity to create activities for SomeWork, StepOne, and StepTwo. Without a collector, StartActivity returns null and no telemetry is collected. ```csharp using System; using System.Diagnostics; using System.Threading.Tasks; namespace Sample.DistributedTracing { class Program { static ActivitySource s_source = new ActivitySource("Sample.DistributedTracing"); static async Task Main(string[] args) { await DoSomeWork(); Console.WriteLine("Example work done"); } static async Task DoSomeWork() { using (Activity? a = s_source.StartActivity("SomeWork")) { await StepOne(); await StepTwo(); } } static async Task StepOne() { using (Activity? a = s_source.StartActivity("StepOne")) { await Task.Delay(500); } } static async Task StepTwo() { using (Activity? a = s_source.StartActivity("StepTwo")) { await Task.Delay(1000); } } } } ``` -------------------------------- ### Install dotnet-dsrouter tool Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-dsrouter Installs the latest release version of the dotnet-dsrouter NuGet package globally using the dotnet tool install command. ```bash dotnet tool install --global dotnet-dsrouter ``` -------------------------------- ### Example of different instrument types in Program.cs Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/metrics-instrumentation Replaces the example code in Program.cs with a complete program that creates a Meter and instruments for counting hats sold, timing order processing, and tracking coats sold and pending orders. It simulates transactions and records metrics. Run with dotnet-counters to view the metrics. ```csharp using System; using System.Diagnostics.Metrics; using System.Threading; class Program { static Meter s_meter = new Meter("HatCo.Store"); static Counter s_hatsSold = s_meter.CreateCounter("hatco.store.hats_sold"); static Histogram s_orderProcessingTime = s_meter.CreateHistogram("hatco.store.order_processing_time"); static int s_coatsSold; static int s_ordersPending; static Random s_rand = new Random(); static void Main(string[] args) { s_meter.CreateObservableCounter("hatco.store.coats_sold", () => s_coatsSold); s_meter.CreateObservableGauge("hatco.store.orders_pending", () => s_ordersPending); Console.WriteLine("Press any key to exit"); while(!Console.KeyAvailable) { // Pretend our store has one transaction each 100ms that each sell 4 hats Thread.Sleep(100); s_hatsSold.Add(4); // Pretend we also sold 3 coats. For an ObservableCounter we track the value in our variable and report it // on demand in the callback s_coatsSold += 3; // Pretend we have some queue of orders that varies over time. The callback for the orders_pending gauge will report // this value on-demand. s_ordersPending = s_rand.Next(0, 20); // Last we pretend that we measured how long it took to do the transaction (for example we could time it with Stopwatch) s_orderProcessingTime.Record(s_rand.Next(5, 15)/1000.0); } } } ``` -------------------------------- ### Install dotnet-stack as a global tool Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-stack Installs the latest release version of the dotnet-stack NuGet package as a global tool using the dotnet tool install command. ```bash dotnet tool install --global dotnet-stack ``` -------------------------------- ### Complete HTTPClient example Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/diagnosticsource-diagnosticlistener Combines the listener creation and guarded write into a complete class. Demonstrates the full pattern for instrumenting a method with DiagnosticSource. ```csharp class HTTPClient { private static DiagnosticSource httpLogger = new DiagnosticListener("System.Net.Http"); public byte[] SendWebRequest(string url) { if (httpLogger.IsEnabled("RequestStart")) { httpLogger.Write("RequestStart", new { Url = url }); } //Pretend this sends an HTTP request to the url and gets back a reply. byte[] reply = new byte[] { }; return reply; } } ``` -------------------------------- ### Sample output for parallel work example Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/eventsource-activity-ids This is the output produced by the preceding C# example. It shows the Activity IDs and Related Activity IDs for each event, demonstrating how the QueryStart events for the two parallel queries are children of the WorkStart event. ```text TID Activity ID Related Activity ID Event Arguments 34276 00000011-0000-0000-0000-000086af9d59 00000000-0000-0000-0000-000000000000 WorkStart A 34276 00001011-0000-0000-0000-0000869f9d59 00000011-0000-0000-0000-000086af9d59 QueryStart SELECT bowls 34276 00002011-0000-0000-0000-0000868f9d59 00000011-0000-0000-0000-000086af9d59 QueryStart SELECT spoons 32684 00002011-0000-0000-0000-0000868f9d59 00000000-0000-0000-0000-000000000000 DebugMessage processing query 18624 00001011-0000-0000-0000-0000869f9d59 00000000-0000-0000-0000-000000000000 DebugMessage processing query 18624 00002011-0000-0000-0000-0000868f9d59 00000000-0000-0000-0000-000000000000 QueryStop 32684 00001011-0000-0000-0000-0000869f9d59 00000000-0000-0000-0000-000000000000 QueryStop 32684 00000011-0000-0000-0000-000086af9d59 00000000-0000-0000-0000-000000000000 WorkStop ``` -------------------------------- ### Launch LLDB Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/lldb-linux Start LLDB with the command appropriate for your distribution (often `lldb`, but some distros require a version number like `lldb-3.9`). The output shows the symbol store settings and the `(lldb)` prompt. ```bash $ lldb Current symbol store settings: -> Cache: /home/username/.dotnet/symbolcache -> Server: https://msdl.microsoft.com/download/symbols/ Timeout: 4 RetryCount: 0 (lldb) ``` -------------------------------- ### Install dotnet-symbol with dotnet tool install Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-symbol Installs the latest release version of the dotnet-symbol NuGet package as a global tool. Requires .NET Core 2.1 SDK or later. ```bash dotnet tool install --global dotnet-symbol ``` -------------------------------- ### ApplyStartupHookAsync(string, CancellationToken) Source: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/microsoft-diagnostics-netcore-client Asynchronously loads the specified assembly with a StartupHook in the target process. ```APIDOC ## ApplyStartupHookAsync(string, CancellationToken) ### Description Asynchronously loads the specified assembly with a StartupHook in the target process. ### Method ApplyStartupHookAsync ### Parameters - **startupHookPath** (string) - Required - The path to the assembly containing the startup hook. - **token** (CancellationToken) - Required - The token to monitor for cancellation requests. ### Returns Task - A task that represents the asynchronous operation. ```