Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Monitor Dotnet

🔍 Monitor Dotnet

Version 1.2.0 .NET net10.0 License MIT

📊 Real-time monitoring for .NET applications in VS Code — CPU load, memory, garbage collection, counters, metrics and environment variables. The monitor opens by itself when you start debugging. No web dashboard, no extra services — everything runs locally.

🇷🇺 Русская версия: README.ru.md · 📋 Changelog: CHANGELOG.md

Monitor Dotnet panel next to the editor: performance charts, detected issues, counters and environment


✨ Features

Feature What you get
📈 Performance charts CPU load, garbage collection and memory drawn live on canvas
🗑️ GC timeline Collection markers coloured by generation, with reason and pause duration
🧮 Range analysis Drag a chart to get min / avg / max, GC count and average pause for the range
🩺 Issue detection Suspicious intervals found automatically, as a native list and as bands on the charts
🧾 EventCounters Classic .NET counters grouped by provider
📐 Metrics System.Diagnostics.Metrics instruments grouped by meter
🌱 Environment Environment variables and system properties of the process
🐞 Debug integration Monitoring starts automatically on .NET debug sessions: coreclr, C# Dev Kit and Aspire
🎯 Process picker Choose which running process to monitor when several applications are launched together
🔌 Attach to process Connect to any running .NET process in two clicks
🧵 Call stack Snapshot the call stack of the running process
💾 Memory snapshot Collect a GCDump and reveal it in the file manager
🧠 Dump analysis Run dotnet-dump SOS commands on a .dmp and get a graphical report with charts
🗂️ Dumps view Every .dmp and .gcdump from the output folder in one list: open one for analysis or compare two files
🧠 Snapshot analysis dotnet-gcdump report for a .gcdump: heap by type in the same panel, with comparison between two snapshots
⏺️ Profiling Record a dotnet-trace profile in the Speedscope format, with a profile and a time limit
🔄 Trace files Convert an existing .nettrace to Speedscope or show its hottest methods
🌍 Two languages English and Russian, following the VS Code display language
📟 Status bar CPU load and private memory always in sight

✅ Requirements

Requirement Why it is needed
🖥️ VS Code 1.100 or newer Webview, localization and tree APIs in use. The minimum is enforced: @types/vscode is pinned to 1.100.0, so the build fails if an API newer than 1.100 is used
🟣 .NET 10 runtime The bundled bridge that reads EventPipe is a net10.0 app, and it is started through dotnet. dotnet must be on PATH, otherwise set monitor-dotnet.dotnetPath
🔬 dotnet-stack, dotnet-gcdump, dotnet-trace, dotnet-dump, dotnet-symbol, dotnet-counters (optional) Needed for a call stack snapshot, memory snapshots, profiling, dumps, symbols and counter export. The extension offers to install a missing tool with one command

For Aspire projects the Aspire CLI has to be installed: it is the CLI that starts the AppHost project. The Aspire extension for VS Code is optional — monitoring attaches to the same process as the debugger.

The application you monitor does not have to be .NET 10: EventPipe has been available since .NET Core 3.0, so .NET 5 apps and newer work as well. Windows, Linux and macOS are supported — private memory, environment variables and the command line are read through platform APIs. Mono and Unity are not supported.


🚀 Quick start

  1. 📦 Install the extension (see Build from source below for a local build).
  2. ⌨️ Press F5 on any .NET project, or run Monitor Dotnet: Start Monitoring from the command palette.
  3. 📊 The Monitor Dotnet panel appears in the activity bar with live charts and counters.

🐞 Debug integration

How the application is started Debug session type Which process is monitored
coreclr launch of an assembly (App.dll) coreclr The application process (apphost or dotnet host)
C# Dev Kit project launch (projectPath in the configuration) dotnet The project's application process, not the dotnet run wrapper
Aspire AppHost (aspire run under the debugger) aspire The AppHost process — the same one the debugger is attached to. Services started by Aspire are not monitored automatically: attach to one with Attach to .NET Process…

Sessions of other .NET types (clr for .NET Framework, dotnet-core) are recognised as well. In an Aspire solution the dashboard, the orchestrator and the CLI are never offered as targets.

F# projects work the same way: Ionide debugs them through the coreclr session and puts the built assembly into program, and the same rules pick the application process. .fsproj is understood wherever a project file can be given. Profiling itself is runtime-level — the bridge reads EventPipe — so the language of the application does not matter.


🎯 Choosing the process

When several applications run together — an Aspire AppHost with its services, or a compound launch — you pick which process to monitor. Process in the panel header lists everything running:

Where the list lives What it shows
Dropdown in the Performance panel Debug sessions first, then other .NET processes, with the monitored one marked with a check mark
Monitor Dotnet: Select Process to Monitor… in the command palette (or the panel toolbar button) The same list with PID and command line, so you can also attach to a process started without a debugger

The process detected for a session is remembered, so switching is instant. Monitoring is never switched behind your back: when a second debug session starts, the first one keeps being monitored and the extension offers to switch. When the monitored session ends, the extension suggests another running process.


📊 Performance panel

Three charts update once per second, plus a row of current-value tiles.

Chart What it shows
📈 CPU load Processor usage of the application; 100 % means all cores fully loaded
🗑️ Garbage collection Allocation rate with markers for every collection: colour = generation, tooltip = reason and pause
🧠 Memory Private memory (area), managed heap and working set
Action Result
🖱️ Hover Tooltip with all series values and GC details in that moment
↔️ Drag Select a time range; a summary appears below with min / avg / max, GC count and average pause
⌨️ Esc or double click Reset the selection
⏸️ Pause Freeze the view to inspect data; Resume pulls a fresh snapshot

Colours come from the current theme, so the panel looks native in light, dark and high-contrast themes.

🩺 Automatic issue detection

The extension watches the charts and marks suspicious time ranges on its own:

Issue When it is reported
🔥 CPU saturation Load stayed at 90 % or more for several refreshes in a row
🗑️ Long GC pause A single pause of 100 ms or more, 300 ms and above is critical
🌊 GC pressure 10 or more collections with 200 ms or more of pauses inside a 10-second window
📈 Allocation spike Allocation rate three times above the session median and at least 1 MB/s

Every issue gets a coloured band on the matching chart and an entry in the list above the charts: the severity badge (ℹ️ info, ⚠️ warning, 🔴 critical), the moment it started and a short explanation. Click an entry to select its time range — the charts zoom out to fit it and the range summary appears underneath. Turn the whole thing off with monitor-dotnet.enableIssueDetection.

The same list lives in the native Issues view next to the charts, with a theme icon per severity and the interval in the description. It works even with the panel closed: clicking an issue opens the charts and selects that interval.

The list is a report of the run, not a slice of the current data. Problems are kept per process: the chart panel and its bands always belong to the process shown on the charts, while the Issues view keeps the history and groups it by process (name and PID, with the monitored one marked, the monitored group expanded first).

Every issue keeps its own data. When the live charts have already moved past an interval — or it belongs to another process — clicking the issue shows that saved interval: the charts are drawn from the stored points with some context around it, a band marks the exact range, the summary below gives min / avg / max and GC numbers, and a banner names the process and offers Back to live data. So an old issue can still be analysed; only the points that were never collected are lost. The next debug session starts the list over, and Clear Collected Data forgets it as well.


🔢 Counters and metrics

The Counters view lists two kinds of data:

  • 🧾 EventCounters — classic counters grouped by provider (System.Runtime, Microsoft.AspNetCore.Hosting, your own EventSource)
  • 📐 Metrics — System.Diagnostics.Metrics instruments grouped by meter, including tagged series

Pick what to collect in the settings:

"monitor-dotnet.counterProviders": [
  "System.Runtime",                  // every counter of the provider
  "MyProvider[Counter1,Counter2]"    // only the listed counters
],
"monitor-dotnet.metricProviders": ["*"]  // all meters, or "MyMeter", or "MyMeter\\MyInstrument"

Right-click any counter, meter or group and choose Add to Collection Filter: the extension updates the matching setting for you and restarts the bridge to apply it.


🌱 Environment

The Environment view shows what the application was started with:

  • 🔤 environment variables of the process
  • 🖥️ system properties: .NET version, startup flags, command line, OS, architecture
  • 🔍 filter by name or value, and copy any value to the clipboard

🛠 Profiling on demand

Buttons in the Performance view title bar:

Button Tool Result
🧵 Collect Call Stack dotnet-stack Call stack of every thread in a new editor tab
💾 Get Memory Snapshot (GCDump) dotnet-gcdump .gcdump file, revealed in the file manager; Analyse Memory Snapshot reads it back as a heap table
🗄️ Take Memory Dump dotnet-dump .dmp file of type Heap: stacks and managed memory for dotnet-dump analyze
⏺️ Start / Stop Performance Profiling dotnet-trace .nettrace and a ready .speedscope.json next to it; the profile and duration come from the settings
🔄 Convert Trace to Speedscope… dotnet-trace Converts a .nettrace from the output folder without recording a new one
🔝 Show Top Methods in Trace… dotnet-trace report topN: the methods that stayed on the call stack the longest
📤 Record Counters to File dotnet-counters CSV or JSON for 30 seconds, 1 minute or 5 minutes
🏷️ Add Line Numbers to Stack Trace dotnet-stack symbolicate: file and line for a stack trace from logs, taken from the editor
🔎 Open Speedscope Profile — Opens the newest .speedscope.json from the output folder (a picker appears if there are several)
⬇️ Download Symbols for Dumps dotnet-symbol PDB/DBG files next to the dumps, so stack traces show function names

Results go to the .monitor-dotnet folder of the project, together with a .gitignore that keeps them out of the repository. Set monitor-dotnet.profilingOutputDirectory to put them somewhere else. If a tool is missing, the extension offers to install it with one command (dotnet tool install --global …).

Dumps and snapshots are analysed from the Dumps view: click a file there (or right-click it in the Explorer) and the graphical report opens.

Dump analysis runs dotnet-dump analyze in non-interactive mode on the newest .dmp from the output folder (or on the file you right-clicked in the Explorer). Pick one or more presets — Overview, Thread stacks, Heap by type, Async and thread pool, Exceptions, Locks and Finalization queue — or Custom SOS commands to type any command, one per line. The dump type is set by monitor-dotnet.dumpType (Full, Heap, Mini, Triage), and monitor-dotnet.dumpCrashReport adds a crash report to it. The result opens in a graphical panel styled like VS Code: overview metrics, automatic findings and a separate interactive panel for every command: a thread table from clrthreads, GC segment sizes from eeheap -gc, a filterable heap table, sync blocks, expandable thread stacks with application frames highlighted, thread pool meters, exception cards with their stacks and the finalization queue grouped by type. Commands shared by several presets are shown once. Any panel can be collapsed with a click, and long lists have search and paging. The Details section keeps only the raw SOS output, and Open text report shows the complete report in an editor tab.

Memory dump analysis: GC heap segments with allocated and committed sizes, heap by type and heap composition with a filterable type table

A dump is a single moment in time, not a time range: the panel shows the process state at the moment the dump was taken. The header shows the dump file time and size separately from the report creation time. The live CPU and memory charts in the Performance panel are the time series; the dump page is one snapshot.

The Dumps view lists every .dmp and .gcdump from the output folder. Click a file to analyse it, or use Compare Dumps… / Compare Memory Snapshots… to pick two files: the report shows what changed in the heap, threads, async state machines and exception objects, with the types that grew or shrank the most. A snapshot is read with dotnet-gcdump report: the same panel, but only heap data — the tool lists objects grouped by exact size, and the extension sums them per type.

When you open a profile for the first time, the extension offers to install Speedscope in VS Code and to add the editor association that makes .speedscope.json files open in that viewer:

"workbench.editorAssociations": {
  "*.speedscope.json": "speedscope-in-vscode.speedscope"
}

Both steps are optional — without the viewer the file opens as plain JSON, and the association can be added later by hand.


⚙️ Settings

Setting Default Description
monitor-dotnet.enableMonitoring onDebugOrRun When to start monitoring: onDebugOrRun, onDebug, never
monitor-dotnet.autoReveal true Open the panel when a debug session starts
monitor-dotnet.refreshIntervalSeconds 1 How often counters and metrics are refreshed
monitor-dotnet.chartWindowSeconds 120 How many seconds of data the charts show
monitor-dotnet.enableIssueDetection true Look for suspicious intervals on the charts
monitor-dotnet.counterProviders base .NET set EventCounters providers
monitor-dotnet.metricProviders ["*"] Meter filters
monitor-dotnet.dotnetPath dotnet Path to the dotnet executable
monitor-dotnet.bridgePath empty Bridge assembly; empty means the bundled copy
monitor-dotnet.processNameFilter empty Extra substring to find the debuggee process
monitor-dotnet.profilingOutputDirectory empty Where profile and snapshot files are written
monitor-dotnet.traceProfile default dotnet-trace profile: dotnet-common, dotnet-sampled-thread-time, gc-verbose, gc-collect or database
monitor-dotnet.traceDurationSeconds 0 Record the profile for this many seconds; 0 records until you stop it
monitor-dotnet.dumpType Heap Dump type for dotnet-dump: Full, Heap, Mini or Triage
monitor-dotnet.dumpCrashReport false Add a crash report to the memory dump

🌍 Languages

The extension speaks the language of your VS Code interface.

  • 🇬🇧 English — source language of every string
  • 🇷🇺 Russian — complete translation
What Where the translation lives
Code strings: notifications, hints, log l10n/bundle.l10n.<language>.json
Manifest: commands, views, settings package.nls.<language>.json
Charts panel (webview) texts are sent by the extension together with data

🏗️ How it works

┌────────────────────────── VS Code ──────────────────────────┐
│  Monitor Dotnet extension (TypeScript)                       │
│                                                              │
│  extension.ts ──► MonitorController ──► Bridge process       │
│                        │                    │ NDJSON (stdout)│
│                        ▼                    ▼                │
│  MonitorState (series, counters, metrics)  BridgeLocator     │
│            │                                                 │
│            ├─► Performance panel   (canvas charts, webview)  │
│            ├─► Counters view       (tree)                    │
│            ├─► Environment view    (tree)                    │
│            └─► Status bar          (CPU and memory)          │
└──────────────────────────────────────────────────────────────┘
                              ▲
                              │ one JSON message per line
                              ▼
┌─────────── Bridge (MonitorDotnet.Bridge, .NET 10) ───────────┐
│  EventPipe session:                                          │
│   • EventCounters                  → provider counters       │
│   • System.Diagnostics.Metrics     → meters                  │
│   • Microsoft-Windows-DotNETRuntime → GC events, heap stats  │
│  Operating system: private memory, environment, command line │
└──────────────────────────────────────────────────────────────┘

A VS Code extension cannot read EventPipe directly, so collection happens in a small .NET process. It attaches to the target process, parses the event stream and sends ready-made samples to the extension.


📁 Project structure

Path Purpose
src/core Framework-free logic: protocol, state, formatting, chart data, debuggee matching
src/monitor Bridge lifecycle, .NET process discovery, profiling tool wrappers
src/views Panels: Performance (webview provider), Counters and Environment (trees), status bar
src/webview Code that runs inside the webview: canvas rendering and message handling
src/extension.ts Activation, commands, debug session handling, context keys
bridge/MonitorDotnet.Bridge .NET 10 bridge: EventPipe session, event parsing, process statistics
bridge/MonitorDotnet.Bridge.Tests Bridge tests, including an end-to-end run against a real process
samples/SampleApp Demo application with counters, metrics and load
samples/WebApi ASP.NET Core web app for checking the coreclr and C# Dev Kit launch styles
samples/AspireApp Aspire AppHost with one service, for checking the aspire debug session
scripts/build.ts Builds the extension and the webview bundle with esbuild
l10n, package.nls.* Translation dictionaries
test Extension tests: activation, localization, end-to-end data flow

🧪 Build from source

Requirements: .NET SDK 10, Node.js 20+, VS Code 1.100+.

npm install
npm run bridge:build   # publish the .NET bridge to media/bridge and dist/bridge
npm run build          # bundle the extension and the charts panel
npm run package        # create monitor-dotnet-1.2.0.vsix
code --install-extension monitor-dotnet-1.2.0.vsix

Useful commands:

Command What it does
npm run watch Rebuild the extension and the panel on change
npm run typecheck Type check with TypeScript 7 (extension and webview separately)
npm test Extension tests, including dictionary consistency
npm run test:bridge Bridge tests with xunit
MONITOR_DOTNET_E2E=1 npm test End-to-end checks on real processes: samples/SampleApp --stress (charts and issue detection), plus samples/WebApi and samples/AspireApp for the debug session types. The CPU overload check needs a free machine: on a busy one it reports that the load never reached the threshold instead of failing

🔐 Privacy

  • 🚫 No telemetry, no accounts, nothing is uploaded: the extension collects data locally and never sends it anywhere. The only network access happens when you confirm it — installing a missing diagnostic tool with dotnet tool install or opening the .NET diagnostics documentation.
  • 🏠 All data is collected locally by the bridge process and shown only inside VS Code.
  • 🗂️ Profile files and memory snapshots are written where you point them (the temporary directory by default).

📄 License

MIT — full text in LICENSE. © 2026 Dmitry Sorokin (dimanrus).

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages