There are so many times you need to get a place where your frozen process stuck aren't?
Especially if this is a production server or remote environment. So what to do?
I have faced this problem myself and created a small tool that gets stack trace from process by its name.
We will need the following instruments:
- Microsoft.Diagnostics.Runtime.dll
- System.Management.dll
And some code to find a process and get its stack trace.
private string CatchStacktrace(string domainName)
{
int pid = -1;
var procs = System.Diagnostics.Process.GetProcessesByName("w3wp");
var proc = procs.FirstOrDefault(p => GetProcessOwner(p.Id).StartsWith(domainName));
if (proc == null)
return string.Format("User Name not found: {0}", domainName);
pid = proc.Id;
if (pid < 1)
return string.Format("Process w3wp.exe not found: {0}", domainName);
StringBuilder sb = new StringBuilder();
sb.AppendLine(domainName);
sb.AppendLine(string.Empty);
using (var tdata = DataTarget.AttachToProcess(pid, 3000))
{
// Dump CLR info
var clrVersion = tdata.ClrVersions.First();
var dacInfo = clrVersion.DacInfo;
sb.AppendLine("# CLR Info");
sb.AppendLine(string.Format("Version: {0}", clrVersion.Version));
sb.AppendLine(string.Format("Filesize: {0:X}", dacInfo.FileSize));
sb.AppendLine(string.Format("Timestamp: {0:X}", dacInfo.TimeStamp));
sb.AppendLine(string.Format("Dac file: {0}", dacInfo.FileName));
sb.AppendLine(string.Empty);
var runtime = clrVersion.CreateRuntime();
var appDomain = runtime.AppDomains.First();
sb.AppendLine(string.Format("# Runtime Info"));
sb.AppendLine(string.Format("AppDomain: {0}", appDomain.Name));
sb.AppendLine(string.Format("Address: {0}", appDomain.Address));
sb.AppendLine(string.Format("Configuration: {0}", appDomain.ConfigurationFile));
sb.AppendLine(string.Format("Directory: {0}", appDomain.ApplicationBase));
sb.AppendLine(string.Empty);
// Dump thread info
sb.AppendLine("## Threads");
sb.AppendLine(string.Format("Thread count: {0}", runtime.Threads.Count));
sb.AppendLine(string.Empty);
foreach (var thread in runtime.Threads)
{
sb.AppendLine(string.Format("### Thread {0}", thread.OSThreadId));
sb.AppendLine(string.Format("Thread type: {0}",
thread.IsBackground ? "Background"
: thread.IsGC ? "GC"
: "Foreground"));
var blocks = thread.BlockingObjects;
if (blocks != null)
{
foreach(var block in blocks)
{
sb.AppendLine(string.Format("Blocked by: {0} reason: {1}", block.ToString(), block.Reason.ToString()));
}
}
sb.AppendLine(string.Empty);
sb.AppendLine("Stack trace:");
foreach (var stackFrame in thread.EnumerateStackTrace())
{
sb.AppendLine(string.Format("* {0}", stackFrame.DisplayString));
}
sb.AppendLine(string.Empty);
sb.AppendLine(string.Empty);
}
}
return sb.ToString();
}
string[] argList = new string[] { string.Empty, string.Empty };
ManagementObjectCollection processList = null;
ManagementObjectSearcher searcher = null;
string query = "Select * From Win32_Process Where ProcessID = ";
public string GetProcessOwner(int processId)
{
searcher = new ManagementObjectSearcher(query + processId);
processList = searcher.Get();
foreach (ManagementObject obj in processList)
{
argList[0] = string.Empty;
argList[1] = string.Empty;
int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList));
if (returnVal == 0)
{
return argList[0];
}
}
return "NO OWNER";
}
As you know asp.net applications all have w3wp process name and run under its own user name usually with the same name as website name. So to find w3wp process we will pass its username like "ok.unsode.com" to the CatchStacktrace method.
If appropriate w3wp process has been found then you will get something like that: