{"id":54189,"date":"2025-11-25T17:15:49","date_gmt":"2025-11-25T17:15:49","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=54189"},"modified":"2026-02-21T08:29:10","modified_gmt":"2026-02-21T08:29:10","slug":"dotnet-trace-a-complete-dotnet-trace-tutorials-guide","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/dotnet-trace-a-complete-dotnet-trace-tutorials-guide\/","title":{"rendered":"dotnet-trace: A Complete dotnet-trace Tutorials Guide"},"content":{"rendered":"\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">1. What is <code>dotnet-trace<\/code>?<\/h2>\n\n\n\n<p><strong>dotnet-trace<\/strong> is a <strong>.NET Core\/ .NET CLI diagnostic tool<\/strong> that collects <strong>runtime traces<\/strong> from your app using <strong>EventPipe<\/strong>.<\/p>\n\n\n\n<p>Think of it as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2705 A <strong>lightweight profiler<\/strong> you can run <strong>in production<\/strong> (no restart needed)<\/li>\n\n\n\n<li>\u2705 A way to capture <strong>CPU, GC, exceptions, thread activity<\/strong>, etc.<\/li>\n\n\n\n<li>\u2705 A tool that generates <code>.nettrace<\/code> files you can open in <strong>PerfView<\/strong>, <strong>Visual Studio<\/strong>, or convert to <strong>speedscope<\/strong> for flame charts.<\/li>\n<\/ul>\n\n\n\n<p>It works for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>.NET Core 3.0+<\/li>\n\n\n\n<li>.NET 5\/6\/7\/8\/9 apps<br>On <strong>Windows \/ Linux \/ macOS<\/strong>.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">2. When to use <code>dotnet-trace<\/code> (Use Cases)<\/h2>\n\n\n\n<p>Use <code>dotnet-trace<\/code> whenever you need to <strong>understand what your .NET process is doing internally<\/strong>:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd39 Common scenarios<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>High CPU investigation<\/strong>\n<ul class=\"wp-block-list\">\n<li>CPU 80\u201390% on production app<\/li>\n\n\n\n<li>You want to know <strong>which methods<\/strong> are consuming CPU.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>GC \/ Memory issues<\/strong>\n<ul class=\"wp-block-list\">\n<li>Frequent GC<\/li>\n\n\n\n<li>High allocation rate<\/li>\n\n\n\n<li>Pauses impacting latency.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Random hangs \/ delays<\/strong>\n<ul class=\"wp-block-list\">\n<li>Requests are slow, but traditional logging doesn\u2019t tell you why.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Startup performance issues<\/strong>\n<ul class=\"wp-block-list\">\n<li>App is slow to start; you want to see what happens during startup.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Comparing before vs after optimizations<\/strong>\n<ul class=\"wp-block-list\">\n<li>Capture a trace before tuning,<\/li>\n\n\n\n<li>Capture another trace after changes,<\/li>\n\n\n\n<li>Compare CPU\/GC patterns.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Lab \/ Training<\/strong>\n<ul class=\"wp-block-list\">\n<li>Teaching .NET runtime internals<\/li>\n\n\n\n<li>Showing real-world behavior of GC, threads, etc.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">3. Where to use <code>dotnet-trace<\/code><\/h2>\n\n\n\n<p>You can use it on:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Local developer machine<\/strong> \u2013 debugging \/ demos<\/li>\n\n\n\n<li><strong>Staging \/ UAT<\/strong> \u2013 reproduce production-like load and trace<\/li>\n\n\n\n<li><strong>Production<\/strong> \u2013 short, targeted traces when you hit an incident\n<ul class=\"wp-block-list\">\n<li>It\u2019s <strong>sampling-based<\/strong> (for CPU) and <strong>event-based<\/strong>, so usually safe if you keep duration limited.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>Works with:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Kestrel apps<\/strong> (ASP.NET Core)<\/li>\n\n\n\n<li><strong>Worker services<\/strong>, console apps<\/li>\n\n\n\n<li><strong>Windows services<\/strong>, Linux systemd services<\/li>\n\n\n\n<li>Apps running in <strong>Docker<\/strong> \/ <strong>Kubernetes<\/strong> (attach using PID inside container).<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">4. How to install <code>dotnet-trace<\/code><\/h2>\n\n\n\n<p>You already ran this, but let\u2019s document it properly.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4.1 Prerequisites<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>.NET SDK installed (you already have <code>dotnet --version<\/code> working).<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">4.2 Install as a global tool<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">dotnet tool install --<span class=\"hljs-keyword\">global<\/span> dotnet-trace\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>If already installed and you want to update:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">dotnet tool update --<span class=\"hljs-keyword\">global<\/span> dotnet-trace\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Verify:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">dotnet-trace --version\ndotnet-trace --help\n<\/code><\/span><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">5. Key Concepts (Before Commands)<\/h2>\n\n\n\n<p>A few basics:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Process ID (PID)<\/strong> \u2013 you attach to a running process using <code>--process-id &lt;pid&gt;<\/code>.<\/li>\n\n\n\n<li><strong>EventPipe<\/strong> \u2013 internal mechanism used to stream runtime events.<\/li>\n\n\n\n<li><strong>Profiles<\/strong> \u2013 preconfigured sets of providers\/events:\n<ul class=\"wp-block-list\">\n<li><code>cpu-sampling<\/code><\/li>\n\n\n\n<li><code>gc-collect<\/code><\/li>\n\n\n\n<li><code>gc-verbose<\/code><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>.nettrace file<\/strong> \u2013 the output that you later inspect or convert.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">6. Basic Commands (dotnet-trace CLI)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">6.1 List processes you can trace<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">dotnet-trace ps\n<\/code><\/span><\/pre>\n\n\n<p>Typical output:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\">12345   <span class=\"hljs-selector-tag\">Orders<\/span><span class=\"hljs-selector-class\">.Api<\/span>\n30280   <span class=\"hljs-selector-tag\">Payments<\/span><span class=\"hljs-selector-class\">.Worker<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Use the PID in <code>collect<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h3 class=\"wp-block-heading\">6.2 Collect a basic trace from a running app<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">dotnet-trace collect --process-id 30280\n<\/code><\/span><\/pre>\n\n\n<p>Default output (e.g., <code>trace.nettrace<\/code>) will be generated in the current directory.<br>Press <strong>Ctrl + C<\/strong> to stop collection.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h3 class=\"wp-block-heading\">6.3 Save trace with custom filename<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">collect<\/span> \n  <span class=\"hljs-selector-tag\">--process-id<\/span> 30280 \n  <span class=\"hljs-selector-tag\">--output<\/span> <span class=\"hljs-selector-tag\">C<\/span><span class=\"hljs-selector-pseudo\">:tracesordersapi_2026-11-25.nettrace<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h3 class=\"wp-block-heading\">6.4 Use a profile (recommended)<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">CPU-focused trace:<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">collect<\/span> \n  <span class=\"hljs-selector-tag\">--process-id<\/span> 30280 \n  <span class=\"hljs-selector-tag\">--profile<\/span> <span class=\"hljs-selector-tag\">cpu-sampling<\/span> \n  <span class=\"hljs-selector-tag\">--duration<\/span> 00<span class=\"hljs-selector-pseudo\">:02<\/span><span class=\"hljs-selector-pseudo\">:00<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Focuses on CPU events<\/li>\n\n\n\n<li>Samples for 2 minutes<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">GC-focused trace:<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">collect<\/span> \n  <span class=\"hljs-selector-tag\">--process-id<\/span> 30280 \n  <span class=\"hljs-selector-tag\">--profile<\/span> <span class=\"hljs-selector-tag\">gc-collect<\/span> \n  <span class=\"hljs-selector-tag\">--duration<\/span> 00<span class=\"hljs-selector-pseudo\">:01<\/span><span class=\"hljs-selector-pseudo\">:00<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h3 class=\"wp-block-heading\">6.5 Start a process and trace it from the beginning<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">collect<\/span> <span class=\"hljs-selector-tag\">--<\/span> <span class=\"hljs-selector-tag\">dotnet<\/span> <span class=\"hljs-selector-tag\">Orders<\/span><span class=\"hljs-selector-class\">.Api<\/span><span class=\"hljs-selector-class\">.dll<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<ul class=\"wp-block-list\">\n<li><code>--<\/code> separates dotnet-trace arguments from the child process command.<\/li>\n\n\n\n<li>dotnet-trace will exit with <strong>the app\u2019s exit code<\/strong>.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h3 class=\"wp-block-heading\">6.6 List available profiles<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">dotnet-trace <span class=\"hljs-keyword\">list<\/span>-profiles\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You\u2019ll see built-in profiles with descriptions.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h3 class=\"wp-block-heading\">6.7 Convert traces to another format (for flame charts)<\/h3>\n\n\n\n<p>Convert <code>.nettrace<\/code> \u2192 speedscope:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">convert<\/span> <span class=\"hljs-selector-tag\">trace<\/span><span class=\"hljs-selector-class\">.nettrace<\/span> <span class=\"hljs-selector-tag\">--format<\/span> <span class=\"hljs-selector-tag\">speedscope<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This produces something like:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">trace<\/span><span class=\"hljs-selector-class\">.speedscope<\/span><span class=\"hljs-selector-class\">.json<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You can open that on <strong>speedscope.app<\/strong> by uploading the JSON file to visualize CPU flame charts.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h3 class=\"wp-block-heading\">6.8 Generate textual reports<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">report<\/span> <span class=\"hljs-selector-tag\">trace<\/span><span class=\"hljs-selector-class\">.nettrace<\/span> <span class=\"hljs-selector-tag\">--report-type<\/span> <span class=\"hljs-selector-tag\">cpu<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Common report types:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>cpu<\/code><\/li>\n\n\n\n<li><code>gc-collect<\/code><\/li>\n\n\n\n<li><code>gc-verbose<\/code><\/li>\n<\/ul>\n\n\n\n<p>Example:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">report<\/span> <span class=\"hljs-selector-tag\">trace<\/span><span class=\"hljs-selector-class\">.nettrace<\/span> <span class=\"hljs-selector-tag\">--report-type<\/span> <span class=\"hljs-selector-tag\">gc-verbose<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">7. Step-by-Step: End-to-End Workflow (Basic)<\/h2>\n\n\n\n<p>Let\u2019s build a simple \u201cincident to analysis\u201d flow.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Scenario: High CPU on Orders.Api<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Identify PID<\/strong> <code>dotnet-trace ps<\/code> Assume you see: <code>30280 Orders.Api<\/code><\/li>\n\n\n\n<li><strong>Collect CPU trace for 2 minutes<\/strong> <code>dotnet-trace collect  --process-id 30280  --profile cpu-sampling  --duration 00:02:00  --output C:tracesorders_highcpu.nettrace<\/code><\/li>\n\n\n\n<li><strong>Convert to speedscope &amp; analyze flame chart<\/strong><code>dotnet-trace convert C:tracesorders_highcpu.nettrace --format speedscope<\/code> This generates a <code>.speedscope.json<\/code>.<br>Then:\n<ul class=\"wp-block-list\">\n<li>Open browser \u2192 speedscope.app<\/li>\n\n\n\n<li>Upload the file<\/li>\n\n\n\n<li>Look at:\n<ul class=\"wp-block-list\">\n<li><strong>Top hot methods<\/strong><\/li>\n\n\n\n<li><strong>Call stacks leading to those methods<\/strong><\/li>\n\n\n\n<li>Identify which controller \/ EF query \/ third-party library eats CPU.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Optional: Generate CPU text report<\/strong> <code>dotnet-trace report C:tracesorders_highcpu.nettrace --report-type cpu<\/code> You get a summary of <strong>top CPU-consuming call stacks<\/strong> in text form.<\/li>\n\n\n\n<li><strong>Apply Fix \u2192 Re-run trace<\/strong>\n<ul class=\"wp-block-list\">\n<li>Optimize that method \/ query<\/li>\n\n\n\n<li>Repeat trace to verify improvement.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">8. Step-by-Step: GC \/ Memory Analysis Workflow<\/h2>\n\n\n\n<p>Scenario: GC is frequently running and latency increases.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Capture GC-focused trace<\/strong> <code>dotnet-trace collect  --process-id 30280  --profile gc-verbose  --duration 00:01:30  --output C:tracesorders_gcverbose.nettrace<\/code><\/li>\n\n\n\n<li><strong>Generate GC report<\/strong> <code>dotnet-trace report C:tracesorders_gcverbose.nettrace --report-type gc-verbose<\/code><\/li>\n\n\n\n<li><strong>Understand the output (key elements)<\/strong><\/li>\n<\/ol>\n\n\n\n<p>Typical info:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Number of <strong>Gen 0 \/ Gen 1 \/ Gen 2 collections<\/strong><\/li>\n\n\n\n<li><strong>LOH (Large Object Heap) allocation \/ collections<\/strong><\/li>\n\n\n\n<li><strong>Pause times<\/strong><\/li>\n\n\n\n<li>Allocation patterns per thread or per call stack.<\/li>\n<\/ul>\n\n\n\n<p>Things to look for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Very frequent <strong>Gen 2<\/strong> collections \u2192 large survival \u2192 potential memory pressure<\/li>\n\n\n\n<li>Large LOH activity \u2192 big arrays \/ big strings (e.g., big JSON \/ images)<\/li>\n\n\n\n<li>Which methods are allocating heavily.<\/li>\n<\/ul>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\">\n<li><strong>Fix candidates:<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Reduce allocations in hot loops<\/li>\n\n\n\n<li>Pool reusable objects<\/li>\n\n\n\n<li>Avoid large temporary lists\/arrays<\/li>\n\n\n\n<li>Fix unbounded caching.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">9. How to Understand dotnet-trace Results (Conceptually)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">9.1 CPU Sampling<\/h3>\n\n\n\n<p>From CPU report and flame charts, you\u2019ll see:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Which methods appear on top<\/strong> (most time spent)<\/li>\n\n\n\n<li><strong>Call chain<\/strong>: e.g.,<br><code>Controller \u2192 Service \u2192 Repository \u2192 EF Core \u2192 SQL<\/code><\/li>\n<\/ul>\n\n\n\n<p>Interpretation:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The <strong>width<\/strong> (in flame chart) or top % (in report) = <strong>how expensive it is<\/strong>.<\/li>\n\n\n\n<li>If business logic \/ EF query dominates:\n<ul class=\"wp-block-list\">\n<li>Optimize queries, add indexes, reduce synchronous blocking, etc.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h3 class=\"wp-block-heading\">9.2 GC\/Memory<\/h3>\n\n\n\n<p>From GC reports:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>High number of collections in short duration \u2192 heavy allocations<\/li>\n\n\n\n<li>Long pause times \u2192 GC pauses affecting latency<\/li>\n\n\n\n<li>Many Gen 2 collections \u2192 objects living too long \/ large memory usage<\/li>\n<\/ul>\n\n\n\n<p>You correlate:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>When GC happens vs request latency<\/li>\n\n\n\n<li>Allocation-heavy methods \u2192 fix them.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h3 class=\"wp-block-heading\">9.3 Using PerfView or Visual Studio<\/h3>\n\n\n\n<p>Although <code>dotnet-trace<\/code> is a CLI collector, the <code>.nettrace<\/code> file can be:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Opened in <strong>PerfView<\/strong><\/li>\n\n\n\n<li>Imported into Visual Studio <strong>Performance Profiler<\/strong> (depending on version)<\/li>\n<\/ul>\n\n\n\n<p>In those tools, you get:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Graphs for CPU over time<\/li>\n\n\n\n<li>GC, threads, exceptions<\/li>\n\n\n\n<li>Call tree, hot paths, etc.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">10. Advanced Usage<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">10.1 Combining with Kubernetes \/ Docker<\/h3>\n\n\n\n<p>Inside a container:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Exec into the pod: <code>kubectl exec -it orders-api-pod-xyz -- \/bin\/bash<\/code><\/li>\n\n\n\n<li>Install dotnet-trace in the container (or via a base image).<\/li>\n\n\n\n<li>List processes: <code>dotnet-trace ps<\/code><\/li>\n\n\n\n<li>Collect from the .NET process inside the container.<\/li>\n<\/ol>\n\n\n\n<p>You can then copy the <code>.nettrace<\/code> file out using:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">kubectl cp <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">namespace<\/span>&gt;<\/span>\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">pod<\/span>&gt;<\/span>:\/path\/inside\/container\/trace.nettrace .\/trace.nettrace\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h3 class=\"wp-block-heading\">10.2 Filtering Providers (Custom EventPipe configs)<\/h3>\n\n\n\n<p>For very advanced scenarios, you can specify providers manually with <code>--providers<\/code>, but most of the time, <strong>profiles<\/strong> are enough. If you want ultra-deep control:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Custom providers (e.g., <code>Microsoft-AspNetCore-Server-Kestrel<\/code>, <code>System.Net.Http<\/code>)<\/li>\n\n\n\n<li>Specific keywords and levels for tracing.<\/li>\n<\/ul>\n\n\n\n<p>Example (indicative):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">collect<\/span> \n  <span class=\"hljs-selector-tag\">--process-id<\/span> 30280 \n  <span class=\"hljs-selector-tag\">--providers<\/span> \"<span class=\"hljs-selector-tag\">Microsoft-AspNetCore-Server-Kestrel<\/span><span class=\"hljs-selector-pseudo\">:0xFFFFFFFF<\/span><span class=\"hljs-selector-pseudo\">:4\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><em>(You\u2019ll usually only do this when you exactly know which ETW\/EventSource providers you want.)<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h3 class=\"wp-block-heading\">10.3 Automating in a Script<\/h3>\n\n\n\n<p>You can create a script, e.g., <code>capture_cpu_trace.ps1<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">$pid = (dotnet-trace ps | Select-<span class=\"hljs-built_in\">String<\/span> <span class=\"hljs-string\">\"Orders.Api\"<\/span>).ToString().Split(<span class=\"hljs-string\">\" \"<\/span>, &#91;System.StringSplitOptions]::RemoveEmptyEntries)&#91;<span class=\"hljs-number\">0<\/span>]\n\ndotnet-trace collect <span class=\"hljs-string\">`\n  --process-id $pid `<\/span>\n  --profile cpu-sampling <span class=\"hljs-string\">`\n  --duration 00:02:00 `<\/span>\n  --output <span class=\"hljs-string\">\"C:tracesorders_cpu_$((Get-Date).ToString('yyyyMMdd_HHmmss')).nettrace\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This lets you quickly capture CPU traces without manually checking PID each time.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">11. Advantages of dotnet-trace<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 1. No code changes required<\/h3>\n\n\n\n<p>You attach to running processes. No need to modify source\/logging.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 2. Low overhead (safe for short runs in production)<\/h3>\n\n\n\n<p>Designed for <strong>live diagnostics<\/strong> with reasonable performance overhead when used carefully.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 3. Works everywhere .NET runs<\/h3>\n\n\n\n<p>Windows, Linux, macOS, Docker, K8s.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 4. Deep runtime insights<\/h3>\n\n\n\n<p>CPU, GC, threads, allocations, exceptions, etc., from the <strong>runtime level<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 5. Integrates with other tools<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>PerfView<\/li>\n\n\n\n<li>Visual Studio profiler<\/li>\n\n\n\n<li>speedscope (flame charts)<\/li>\n\n\n\n<li>Other trace analysis tools that support <code>.nettrace<\/code> or converted formats.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 6. Perfect for training \/ labs<\/h3>\n\n\n\n<p>You can <strong>demonstrate<\/strong> effect of code changes, GC settings, async vs sync, etc., visually.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">12. Quick dotnet-trace Cheatsheet (Summary)<\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"># <span class=\"hljs-selector-tag\">List<\/span> <span class=\"hljs-selector-class\">.NET<\/span> <span class=\"hljs-selector-tag\">processes<\/span>\n<span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">ps<\/span>\n\n# <span class=\"hljs-selector-tag\">Collect<\/span> <span class=\"hljs-selector-tag\">basic<\/span> <span class=\"hljs-selector-tag\">trace<\/span>\n<span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">collect<\/span> <span class=\"hljs-selector-tag\">--process-id<\/span> &lt;<span class=\"hljs-selector-tag\">pid<\/span>&gt;\n\n# <span class=\"hljs-selector-tag\">Collect<\/span> <span class=\"hljs-selector-tag\">CPU<\/span> <span class=\"hljs-selector-tag\">trace<\/span> <span class=\"hljs-selector-tag\">for<\/span> 2 <span class=\"hljs-selector-tag\">min<\/span>\n<span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">collect<\/span> <span class=\"hljs-selector-tag\">--process-id<\/span> &lt;<span class=\"hljs-selector-tag\">pid<\/span>&gt; <span class=\"hljs-selector-tag\">--profile<\/span> <span class=\"hljs-selector-tag\">cpu-sampling<\/span> <span class=\"hljs-selector-tag\">--duration<\/span> 00<span class=\"hljs-selector-pseudo\">:02<\/span><span class=\"hljs-selector-pseudo\">:00<\/span> <span class=\"hljs-selector-tag\">--output<\/span> <span class=\"hljs-selector-tag\">cpu<\/span><span class=\"hljs-selector-class\">.nettrace<\/span>\n\n# <span class=\"hljs-selector-tag\">Collect<\/span> <span class=\"hljs-selector-tag\">GC-verbose<\/span> <span class=\"hljs-selector-tag\">trace<\/span>\n<span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">collect<\/span> <span class=\"hljs-selector-tag\">--process-id<\/span> &lt;<span class=\"hljs-selector-tag\">pid<\/span>&gt; <span class=\"hljs-selector-tag\">--profile<\/span> <span class=\"hljs-selector-tag\">gc-verbose<\/span> <span class=\"hljs-selector-tag\">--duration<\/span> 00<span class=\"hljs-selector-pseudo\">:01<\/span><span class=\"hljs-selector-pseudo\">:00<\/span> <span class=\"hljs-selector-tag\">--output<\/span> <span class=\"hljs-selector-tag\">gc<\/span><span class=\"hljs-selector-class\">.nettrace<\/span>\n\n# <span class=\"hljs-selector-tag\">Run<\/span> <span class=\"hljs-selector-tag\">an<\/span> <span class=\"hljs-selector-tag\">app<\/span> <span class=\"hljs-selector-tag\">and<\/span> <span class=\"hljs-selector-tag\">trace<\/span> <span class=\"hljs-selector-tag\">it<\/span>\n<span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">collect<\/span> <span class=\"hljs-selector-tag\">--<\/span> <span class=\"hljs-selector-tag\">dotnet<\/span> <span class=\"hljs-selector-tag\">MyApp<\/span><span class=\"hljs-selector-class\">.dll<\/span>\n\n# <span class=\"hljs-selector-tag\">List<\/span> <span class=\"hljs-selector-tag\">built-in<\/span> <span class=\"hljs-selector-tag\">profiles<\/span>\n<span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">list-profiles<\/span>\n\n# <span class=\"hljs-selector-tag\">Convert<\/span> <span class=\"hljs-selector-tag\">to<\/span> <span class=\"hljs-selector-tag\">speedscope<\/span>\n<span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">convert<\/span> <span class=\"hljs-selector-tag\">cpu<\/span><span class=\"hljs-selector-class\">.nettrace<\/span> <span class=\"hljs-selector-tag\">--format<\/span> <span class=\"hljs-selector-tag\">speedscope<\/span>\n\n# <span class=\"hljs-selector-tag\">CPU<\/span> <span class=\"hljs-selector-tag\">report<\/span>\n<span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">report<\/span> <span class=\"hljs-selector-tag\">cpu<\/span><span class=\"hljs-selector-class\">.nettrace<\/span> <span class=\"hljs-selector-tag\">--report-type<\/span> <span class=\"hljs-selector-tag\">cpu<\/span>\n\n# <span class=\"hljs-selector-tag\">GC-verbose<\/span> <span class=\"hljs-selector-tag\">report<\/span>\n<span class=\"hljs-selector-tag\">dotnet-trace<\/span> <span class=\"hljs-selector-tag\">report<\/span> <span class=\"hljs-selector-tag\">gc<\/span><span class=\"hljs-selector-class\">.nettrace<\/span> <span class=\"hljs-selector-tag\">--report-type<\/span> <span class=\"hljs-selector-tag\">gc-verbose<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>1. What is dotnet-trace? dotnet-trace is a .NET Core\/ .NET CLI diagnostic tool that collects runtime traces from your app using EventPipe. Think of it as: It works for: 2&#8230;. <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[11138],"tags":[],"class_list":["post-54189","post","type-post","status-publish","format-standard","hentry","category-best-tools"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54189","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=54189"}],"version-history":[{"count":2,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54189\/revisions"}],"predecessor-version":[{"id":59886,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54189\/revisions\/59886"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=54189"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=54189"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=54189"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}