It is possible to get stacktrace using System.Diagnostics.StackTrace, but thread has to be suspended. Suspend and Resume function are obsolete, so I expect that better way exists.
You can obtain a stack trace from a thread – by calling the getStackTrace method on that Thread instance. This invocation returns an array of StackTraceElement, from which details about stack frames of the thread can be extracted.
Analyze external stack tracesFrom the main menu, select Code | Analyze Stack Trace or Thread Dump. In the Analyze Stack Trace dialog that opens, paste the external stack trace or thread dump into the Put a stacktrace here: text area. Click OK. The stack trace is displayed in the Run tool window.
Stack trace error is a generic term frequently associated with long error messages. The stack trace information identifies where in the program the error occurs and is helpful to programmers. For users, the long stack track information may not be very useful for troubleshooting web errors.
The StackTrace property returns the frames of the call stack that originate at the location where the exception was thrown. You can obtain information about additional frames in the call stack by creating a new instance of the System. Diagnostics. StackTrace class and using its StackTrace. ToString method.
NB: Skip to the bottom of this answer for an update.
Here's what's worked for me so far:
StackTrace GetStackTrace (Thread targetThread) { StackTrace stackTrace = null; var ready = new ManualResetEventSlim(); new Thread (() => { // Backstop to release thread in case of deadlock: ready.Set(); Thread.Sleep (200); try { targetThread.Resume(); } catch { } }).Start(); ready.Wait(); targetThread.Suspend(); try { stackTrace = new StackTrace (targetThread, true); } catch { /* Deadlock */ } finally { try { targetThread.Resume(); } catch { stackTrace = null; /* Deadlock */ } } return stackTrace; }
If it deadlocks, the deadlock is automatically freed and you get back a null trace. (You can then call it again.)
I should add that after a few days of testing, I've only once been able to create a deadlock on my Core i7 machine. Deadlocks are common, though, on single-core VM when the CPU runs at 100%.
Update: This approach works only for .NET Framework. In .NET Core and .NET 5+, Suspend
and Resume
cannot be called, so you must use an alternative approach such as Microsoft's ClrMD library. Add a NuGet reference to the Microsoft.Diagnostics.Runtime package; then you can call DataTarget.AttachToProcess
to obtain information about threads and stacks. Note that you cannot sample your own process, so you must start another process, but that is not difficult. Here is a basic Console demo that illustrates the process, using a redirected stdout to send the stack traces back to the host:
using Microsoft.Diagnostics.Runtime; using System.Diagnostics; using System.Reflection; if (args.Length == 3 && int.TryParse (args [0], out int pid) && int.TryParse (args [1], out int threadID) && int.TryParse (args [2], out int sampleInterval)) { // We're being called from the Process.Start call below. ThreadSampler.Start (pid, threadID, sampleInterval); } else { // Start ThreadSampler in another process, with 100ms sampling interval var startInfo = new ProcessStartInfo ( Path.ChangeExtension (Assembly.GetExecutingAssembly().Location, ".exe"), Process.GetCurrentProcess().Id + " " + Thread.CurrentThread.ManagedThreadId + " 100") { RedirectStandardOutput = true, CreateNoWindow = true }; var proc = Process.Start (startInfo); proc.OutputDataReceived += (sender, args) => Console.WriteLine (args.Data != "" ? " " + args.Data : "New stack trace:"); proc.BeginOutputReadLine(); // Do some work to test the stack trace sampling Demo.DemoStackTrace(); // Kill the worker process when we're done. proc.Kill(); } class Demo { public static void DemoStackTrace() { for (int i = 0; i < 10; i++) { Method1(); Method2(); Method3(); } } static void Method1() { Foo(); } static void Method2() { Foo(); } static void Method3() { Foo(); } static void Foo() => Thread.Sleep (100); } static class ThreadSampler { public static void Start (int pid, int threadID, int sampleInterval) { DataTarget target = DataTarget.AttachToProcess (pid, false); ClrRuntime runtime = target.ClrVersions [0].CreateRuntime(); while (true) { // Flush cached data, otherwise we'll get old execution info. runtime.FlushCachedData(); foreach (ClrThread thread in runtime.Threads) if (thread.ManagedThreadId == threadID) { Console.WriteLine(); // Signal new stack trace foreach (var frame in thread.EnumerateStackTrace().Take (100)) if (frame.Kind == ClrStackFrameKind.ManagedMethod) Console.WriteLine (" " + frame.ToString()); break; } Thread.Sleep (sampleInterval); } } }
This is the mechanism that LINQPad 6+ uses to show live execution tracking in queries (with additional checks, metadata probing and a more elaborate IPC).
This is an old Thread, but just wanted to warn about the proposed solution: The Suspend and Resume solution does not work - I just experienced a deadlock in my code trying the sequence Suspend/StackTrace/Resume.
The Problem is that StackTrace constructor does RuntimeMethodHandle -> MethodBase conversions, and this changes a internal MethodInfoCache, which takes a lock. The deadlock occurred because the thread I was examining also was doing reflection, and was holding that lock.
It is a pity that the suspend/resume stuff is not done inside the StackTrace constructor -then this problem could easily have been circumvented.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With