Use dotnet-dump command line tool to capture process dumps
Occasionally I have to dig through process dumps to find some nasty difficult to sort out bug. In the past I used the Task manager and right click to create a dump file
which works fine, but sometimes that turns into several process dumps over time and from different processes at the same time. This repetitive work takes minutes of my day, so why not spend hours finding an automated solution!
Enter dotnet-dump
Using dotnet-dump it's easy peasy to create dump files from .NET Core 3.x and .NET 5+, and it's the same tool for whatever platform you're on.
Installing
You need to have have .NET whatever version SDK installed to install the tool, so if you haven't done that yet go download and install. Once that is in place you can install dotnet-dump. It's installed as a global command line tool by running the following in command line
dotnet tool install --global dotnet-dump
It's a different download for x64, x86 and arm etc. so pick the one that matches your application.
Dumping
After that you can create a dump of a process by running
dotnet-dump collect --process-id 123
That seems easy enough it wasn't for the process id. The dotnet-dump comes with a ps command for that:
PS C:\Windows\system32> dotnet-dump ps
972 dotnet C:\Program Files\dotnet\dotnet.exe
1856 dotnet C:\Program Files\dotnet\dotnet.exe
3044 dotnet C:\Program Files\dotnet\dotnet.exe
3264 dotnet C:\Program Files\dotnet\dotnet.exe
3384 w3wp C:\Windows\SysWOW64\inetsrv\w3wp.exe
5440 w3wp C:\Windows\SysWOW64\inetsrv\w3wp.exe
5592 w3wp C:\Windows\SysWOW64\inetsrv\w3wp.exe
6088 w3wp C:\Windows\SysWOW64\inetsrv\w3wp.exe
9628 w3wp c:\windows\system32\inetsrv\w3wp.exe
Which is good for listing what processes the tool supports, but I need a bit more information. The processes I'm dumping are on a server with several different ASP.NET Core applications running and as you can see there's four different dotnet-processes runnning (the w3wp are IIS worker processes and I don't need those).
The Search for a one-liner PowerShell call
Getting the process the PowerShell way
To get more information about a process I can use PowerShell's Get-Process
PS C:\Windows\system32> Get-Process
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
3382 139 55652 114568 1 011,17 2084 0 ccSvcHst
538 32 209860 200304 1 156,50 2116 0 ccSvcHst
481 36 7160 5136 1,50 4072 2 ccSvcHst
475 35 6664 5708 0,30 8800 7 ccSvcHst
484 36 6852 3948 0,52 10152 6 ccSvcHst
88 7 5260 9380 0,03 1408 0 conhost
That returns every process so it's quite a lengthy list, but as a start Get-Process can filter by name
PS C:\Windows\system32> Get-Process -Name dotnet
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
626 135 100312 139240 34,88 972 0 dotnet
606 137 100612 140280 37,98 1856 0 dotnet
558 91 66268 100420 11,33 3044 0 dotnet
546 91 69588 104200 10,42 3264 0 dotnet
737 102 106256 140772 12,58 6800 0 dotnet
That's better, but it's still missing the application pool information. Luckily for me the application pools are run under the default user names so if I also add to output the name I can see those
PS C:\Windows\system32> Get-Process -Name dotnet -IncludeUserName
Handles WS(K) CPU(s) Id UserName ProcessName
------- ----- ------ -- -------- -----------
632 139224 34,89 972 IIS APPPOOL\Datema ... dotnet
620 140312 38,06 1856 IIS APPPOOL\Datema ESC dotnet
555 100436 11,39 3044 IIS APPPOOL\Datema ... dotnet
538 104144 10,53 3264 IIS APPPOOL\Datema ESC dotnet
740 140760 12,58 6800 IIS APPPOOL\Datema ... dotnet
There they are, but some of the longer ones are cropped "IIS APPPOOL\Datema ...". Well there's some more PowerShell magic that can format the returned table
PS C:\Windows\system32> Get-Process -Name dotnet -IncludeUserName | Format-Table -Wrap -AutoSize
Handles WS(K) CPU(s) Id UserName ProcessName
------- ----- ------ -- -------- -----------
424 77572 2,58 3268 IIS APPPOOL\Datema ESC dotnet
595 123852 12,42 3572 IIS APPPOOL\Datema ES License dotnet
460 72296 2,09 3820 IIS APPPOOL\Datema ESC 2.0 dotnet
659 127604 8,69 10432 IIS APPPOOL\Datema ESC dotnet
First of all the |
character is called a pipe character. It takes the result of the previous command (Get-Process) and moves it into the next command (Format-Table). PowerShell is a object based language so it's actually passing an object that contains rows and properties and those properties can be accessed individually, which we use when it's time to filter the output. To filter the output from Get-Process we can pipe it to Where-object
PS C:\Windows\system32> Get-Process -Name dotnet -IncludeUserName | Where-Object UserName -like 'IIS APPPOOL\Datema ESC 2.0' | Format-Table -Wrap -AutoSize
Handles WS(K) CPU(s) Id UserName ProcessName
------- ----- ------ -- -------- -----------
662 128160 8,77 7540 IIS APPPOOL\Datema ESC 2.0 dotnet
I first I tried to use -eq
for comparison and that worked for for 'IIS APPPOOL\Datema ESC' but not for 'IIS APPPool ESC 2.0'. As far as I can guess it's just not exactly the same for some reason, but luckily there's -like
which works fine.
It's also important to know that the Format-Table -Wrap -AutoSize
needs to be last or the result is empty.
So connecting that to dotnet-dump required a lot of trial and error but this is the result
PS C:\Windows\system32> Get-Process -Name dotnet -IncludeUserName | Where-Object UserName -like 'IIS APPPOOL\Datema ESC' | ForEach { & "dotnet-dump" @("collect", "--process-id", $_.Id) }
Writing full to C:\Windows\system32\dump_20210520_121145.dmp
Complete
Writing full to C:\Windows\system32\dump_20210520_121154.dmp
Complete
Notice I'm actually calling this for the application pool DATEMA ESC since I wanted to see that it actually worked for more than one result. Anyways to parse what's happening there at the end. The ForEach can take a script block which will be executed for each result in the previous call. Inside that script block is the call operator &
which calls a command. I use it since dotnet-dump as far as I know isn't a PowerShell command and can't handle objects piped into it. The call operator first takes an optional path, the command or application, and last the arguments. I excluded the path, the command is "dotnet-dump"
, and the arguments is an array of strings which can be created in PowerShell with the @
character.
Since this achieved my goal I stopped there, but the above could be re-written as a script or possibly made into an alias, I really don't know. Here ends my PowerShell knowledge :)
I am a developer, a AIK Hockey fan and an avid TV-viewer and this is my blog.
No feedback yet
Form is loading...