51

As part of some error handling in our product, we'd like to dump some stack trace information. However, we experience that many users will simply take a screenshot of the error message dialog instead of sending us a copy of the full report available from the program, and thus I'd like to make some minimal stack trace information available in this dialog.

A .NET stack trace on my machine looks like this:

at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, Int32 bufferSize)
at System.IO.StreamReader..ctor(String path)
at LVKWinFormsSandbox.MainForm.button1_Click(Object sender, EventArgs e) in C:\Dev\VS.NET\Gatsoft\LVKWinFormsSandbox\MainForm.cs:line 36

I have this question:

The format looks to be this:

at <class/method> [in file:line ##]

However, the at and in keywords, I assume these will be localized if they run, say, a norwegian .NET runtime instead of the english one I have installed.

Is there any way for me to pick apart this stack trace in a language-neutral manner, so that I can display only the file and line number for those entries that have this?

In other words, I'd like this information from the above text:

C:\Dev\VS.NET\Gatsoft\LVKWinFormsSandbox\MainForm.cs:line 36

Any advice you can give will be helpful.

Sergio Acosta
  • 11,109
  • 12
  • 58
  • 89
Lasse V. Karlsen
  • 350,178
  • 94
  • 582
  • 779
  • 1
    I wish someone would have given the parsing answer for this as I'm working with logged strings from arbitrary applications and was really hoping to get some detail on this. Given you have control of the source of the StackTrace you have indeed picked the correct answer though :) – TheXenocide Sep 18 '12 at 13:44

5 Answers5

71

You should be able to get a StackTrace object instead of a string by saying

var trace = new System.Diagnostics.StackTrace(exception);

You can then look at the frames yourself without relying on the framework's formatting.

See also: StackTrace reference

David Schmitt
  • 54,766
  • 26
  • 117
  • 159
Curt Hagenlocher
  • 19,870
  • 8
  • 56
  • 49
  • Oooh, nice, I didn't know that! I'll definitely look into this. – Lasse V. Karlsen Sep 09 '08 at 13:55
  • In release mode are you still able to get stack trace of an exception precisely? – yusuf Mar 16 '09 at 09:15
  • I serialize **exception** in file. `SerializationHelper.Serialize(@"c:\temp\ConfigurationErrorsExceptions.ser", ex);` If I deserialize from file `var exception = SerializationHelper.Deserialize(@"ConfigurationErrorsExceptions.ser");` ***Trace*** is _not available_ `var trace = new System.Diagnostics.StackTrace(exception as Exception);` the **FrameCount** is 0 – Kiquenet Oct 13 '15 at 09:58
28

Here is the code I use to do this without an exception

public static void LogStack()
{
  var trace = new System.Diagnostics.StackTrace();
  foreach (var frame in trace.GetFrames())
  {
    var method = frame.GetMethod();
    if (method.Name.Equals("LogStack")) continue;
    Log.Debug(string.Format("{0}::{1}", 
        method.ReflectedType != null ? method.ReflectedType.Name : string.Empty,
        method.Name));
  }
}
Lindholm
  • 281
  • 3
  • 2
19

Just to make this a 15 sec copy-paste answer:

static public string StackTraceToString()
{
    StringBuilder sb = new StringBuilder(256);
    var frames = new System.Diagnostics.StackTrace().GetFrames();
    for (int i = 1; i < frames.Length; i++) /* Ignore current StackTraceToString method...*/
    {
        var currFrame = frames[i];
        var method = currFrame.GetMethod();
        sb.AppendLine(string.Format("{0}:{1}",                    
            method.ReflectedType != null ? method.ReflectedType.Name : string.Empty,
            method.Name));
    }
    return sb.ToString();
}

(based on Lindholm answer)

chkimes
  • 1,077
  • 12
  • 19
Hertzel Guinness
  • 5,642
  • 2
  • 35
  • 43
  • 3
    Thanks for that. Note that you can use sb.AppendLine(...) to avoid hardcoding the specific end of line character. – Lee Oades May 30 '12 at 09:25
8

Or there is even shorter version..

Console.Write(exception.StackTrace);
Michał Powaga
  • 20,726
  • 7
  • 45
  • 60
Aftershock
  • 4,598
  • 3
  • 47
  • 59
1

As alternative, log4net, though potentially dangerous, has given me better results than System.Diagnostics. Basically in log4net, you have a method for the various log levels, each with an Exception parameter. So, when you pass the second exception, it will print the stack trace to whichever appender you have configured.

example: Logger.Error("Danger!!!", myException );

The output, depending on configuration, looks something like

System.ApplicationException: Something went wrong.
   at Adapter.WriteToFile(OleDbCommand cmd) in C:\Adapter.vb:line 35
   at Adapter.GetDistributionDocument(Int32 id) in C:\Adapter.vb:line 181
   ...
Greg Ogle
  • 6,368
  • 8
  • 40
  • 61
  • Could you clarify what you mean about log4net being "potentially dangerous"? – Scott Lawrence Sep 09 '08 at 13:33
  • I don't know for sure what Oglester meant, but I know stackoverflow.com had some deadlock problems because log4net was logging exceptions to a database. I haven't personally had any problems, but I keep it simple and stick to rolling text files. – Don Kirkby Sep 17 '08 at 05:29
  • If you do not manage your references properly, you'll end up with a memory leak. The web site I worked on a while back uses log4net extensively (rolling files). Because log4net references file (unsafe), you must be sure to keep log4net references cleaned up or to a minumum. – Greg Ogle Oct 02 '08 at 13:09