How to print the current Stack Trace in .NET without any exception?
Have a look at the System.Diagnostics
namespace. Lots of goodies in there!
System.Diagnostics.StackTrace t = new System.Diagnostics.StackTrace();
This is really good to have a poke around in to learn what's going on under the hood.
I'd recommend that you have a look into logging solutions (Such as NLog, log4net or the Microsoft patterns and practices Enterprise Library) which may achieve your purposes and then some.
Print stack trace with line numbers
You need to pass true
to the constructor to instruct it to capture file/line information.
Alternatively, use Environment.StackTrace
, if you just need the textual representation of the stack trace.
Additionally, the matching .pdb
file must be in the expected location (usually next to the binary).
Print stack trace information from C#
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
How to print full stack trace in exception?
I usually use the .ToString()
method on exceptions to present the full exception information (including the inner stack trace) in text:
catch (MyCustomException ex)
{
Debug.WriteLine(ex.ToString());
}
Sample output:
ConsoleApplication1.MyCustomException: some message .... ---> System.Exception: Oh noes!
at ConsoleApplication1.SomeObject.OtherMethod() in C:\ConsoleApplication1\SomeObject.cs:line 24
at ConsoleApplication1.SomeObject..ctor() in C:\ConsoleApplication1\SomeObject.cs:line 14
--- End of inner exception stack trace ---
at ConsoleApplication1.SomeObject..ctor() in C:\ConsoleApplication1\SomeObject.cs:line 18
at ConsoleApplication1.Program.DoSomething() in C:\ConsoleApplication1\Program.cs:line 23
at ConsoleApplication1.Program.Main(String[] args) in C:\ConsoleApplication1\Program.cs:line 13
Attach StackTrace To Exception Without Throwing in C# / .NET
There is an even more sophisticated solution that avoids any runtime overhead of the reflection part:
public static class ExceptionExtensions
{
public static Exception SetStackTrace(this Exception target, StackTrace stack) => _SetStackTrace(target, stack);
private static readonly Func<Exception, StackTrace, Exception> _SetStackTrace = new Func<Func<Exception, StackTrace, Exception>>(() =>
{
ParameterExpression target = Expression.Parameter(typeof(Exception));
ParameterExpression stack = Expression.Parameter(typeof(StackTrace));
Type traceFormatType = typeof(StackTrace).GetNestedType("TraceFormat", BindingFlags.NonPublic);
MethodInfo toString = typeof(StackTrace).GetMethod("ToString", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { traceFormatType }, null);
object normalTraceFormat = Enum.GetValues(traceFormatType).GetValue(0);
MethodCallExpression stackTraceString = Expression.Call(stack, toString, Expression.Constant(normalTraceFormat, traceFormatType));
FieldInfo stackTraceStringField = typeof(Exception).GetField("_stackTraceString", BindingFlags.NonPublic | BindingFlags.Instance);
BinaryExpression assign = Expression.Assign(Expression.Field(target, stackTraceStringField), stackTraceString);
return Expression.Lambda<Func<Exception, StackTrace, Exception>>(Expression.Block(assign, target), target, stack).Compile();
})();
}
How to hide the current method from exception stack trace in .NET?
Maybe you could derive your own exception type and override the StackTrace
property getter to exclude your method:
using System;
using System.Collections.Generic;
class MyException : Exception {
string _excludeFromStackTrace;
public MyException(string excludeFromStackTrace) {
_excludeFromStackTrace = excludeFromStackTrace;
}
public override string StackTrace {
get {
List<string> stackTrace = new List<string>();
stackTrace.AddRange(base.StackTrace.Split(new string[] {Environment.NewLine},StringSplitOptions.None));
stackTrace.RemoveAll(x => x.Contains(_excludeFromStackTrace));
return string.Join(Environment.NewLine, stackTrace.ToArray());
}
}
}
class Program {
static void TestExc() {
throw new MyException("Program.TestExc");
}
static void foo() {
TestExc();
}
static void Main(params string[] args) {
try{
foo();
} catch (Exception exc){
Console.WriteLine(exc.StackTrace);
}
}
}
How to enable stack trace output for JakartaEE/Glassfish application?
First you tell the web-server that you want to us a custom error page by specifying it in your web.xml
:
web.xml:
<web-app>
<!-- Any unhandled (i.e. Throwable) errors, display the page ysod.jsp (rather than the built-in default -->
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/ysod.jsp</location>
</error-page>
</web-app>
And then you create a new Yellow Screen of Death JSP file:
ysod.jsp
<!DOCTYPE html>
<%@page import="java.io.PrintWriter"%>
<%@page import="java.io.StringWriter"%>
<%@page import="java.io.StringWriter"%>
<%@page isErrorPage="true" %>
<%!
public String htmlEncode(String s)
{
//Java does not have any htmlEncode or escapeHtml (https://stackoverflow.com/a/1400705/12597)
return s;
}
%>
<%
Throwable cause = exception;
while (cause.getCause() != null)
{
cause = cause.getCause();
}
String path = "/";
String message = cause.getMessage(); //e.g ."Division by zero error";
String exceptionClassName = exception.getClass().getName(); // e.g. "EOverflow";
String sourceFile = "$(sourceFile:C:\\website\\WebSite\\src\\FrobTheGrobber.java)";
String sourceLine = "$(sourceLine:619)";
String serverInfo = getServletContext().getServerInfo().trim(); //e.g. "Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.34209"
String javaVersion = System.getProperty("java.version");
StringWriter sw = new StringWriter();
exception.printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
StackTraceElement[] stes = exception.getStackTrace();
if (stes.length > 0)
{
StackTraceElement st = stes[0];
sourceFile = st.getFileName();
sourceLine = Integer.valueOf(st.getLineNumber()).toString();
}
%>
<html>
<head>
<title><%= htmlEncode(message)%></title>
<meta name='viewport' content='width=device-width' />
<style>
body {
font-family:'Verdana';
font-weight:normal;
font-size: .7em;
color:black;
}
p {
font-family:'Verdana';
font-weight:normal;
color:black;
margin-top: -5px;
}
b {
font-family:'Verdana';
font-weight:bold;
color:black;
margin-top: -5px;
}
H1 {
font-family:'Verdana';
font-weight:normal;
font-size:18pt;
color:red;
}
H2 {
font-family:'Verdana';
font-weight:normal;
font-size:14pt;
color:maroon;
}
pre {
font-family:'Consolas','Lucida Console',Monospace;
font-size:11pt;
margin:0;
padding:0.5em;
line-height:14pt;
}
.marker {
font-weight: bold;
color: black;
text-decoration: none;
}
.version {
color: gray;
}
.error {
margin-bottom: 10px;
}
.expandable {
text-decoration:underline;
font-weight:bold;
color:navy;
cursor: grab;
}
@media screen and (max-width: 639px) {
pre {
width: 440px;
overflow: auto;
white-space: pre-wrap;
word-wrap: break-word;
}
}
@media screen and (max-width: 479px) {
pre {
width: 280px;
}
}
</style>
</head>
<body bgcolor='white'>
<span><H1>Server Error in '<%=htmlEncode(path)%>' Application.<hr width=100% size=1 color=silver></H1>
<h2> <i><%=htmlEncode(message)%></i> </h2></span>
<font face='Arial, Helvetica, Geneva, SunSans-Regular, sans-serif'>
<b> Description: </b>An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
<br><br>
<b> Exception Details: </b><%=htmlEncode(exceptionClassName)%>: <%=htmlEncode(message)%><br><br>
<br>
<!--
<b> Source Error: </b>
<table width=100% bgcolor='#ffffcc'>
<tr>
<td>
<code><pre>
</pre></code>
</td>
</tr>
</table>
-->
<b> Source File: </b> <%=htmlEncode(sourceFile)%><b> Line: </b> <%=htmlEncode(sourceLine)%>
<br><br>
<b>Stack Trace:</b> <br><br>
<table width=100% bgcolor='#ffffcc'>
<tr>
<td>
<code><pre>
<%=htmlEncode(stackTrace)%>
</pre></code>
</td>
</tr>
</table>
<br>
<hr width=100% size=1 color=silver>
<b>Version Information:</b> <%=htmlEncode(serverInfo)%>; Java Version: <%=htmlEncode(javaVersion)%>
</font>
</body>
</html>
And Bob's your uncle - a useful error page:
How to get full stack trace from exception object, when debugging in windbg?
TLDR;
You can show the stack trace of a thrown exception using !pe
. In probably more than 90% of the cases that's all you need.
Simple and complete example
Here's a minimal reproducible example:
using System;
namespace ConsoleNetFramework
{
class Program
{
static void Main()
{
throw new ApplicationException("An exception");
}
}
}
and the debugging session:
0:000> .loadby sos clr
0:000> !pe
Exception object: 0335246c
Exception type: System.ApplicationException
Message: An exception
InnerException: <none>
StackTrace (generated):
SP IP Function
012FEFB0 01720897 ConsoleNetFramework!ConsoleNetFramework.Program.Main()+0x4f
StackTraceString: <none>
HResult: 80131600
Complex example
Since I considered the answer to be too simple, I felt free to make it more interesting by adding more seldom cases to the example like so:
static void Main()
{
var b = new BadImageFormatException("Bad exception");
ApplicationException a;
try
{
throw new ApplicationException("An exception");
}
catch (ApplicationException aex)
{
a = aex;
}
var t = new Thread(ThrowAnotherException);
t.Start();
throw new DataException("Data exception");
Console.WriteLine(b.Message);
Console.WriteLine(a.Message);
}
private static void ThrowAnotherException()
{
throw new ConfigurationException("Config exception");
}
In the end we'll have 4 exception objects in memory:
A...Exception
B...Exception
C...Exception
D...Exception
and we can have a look at all of them.
The debugging session is:
0:000> .loadby sos clr
0:000> !pe
Exception object: 02eb2ca8
Exception type: System.Data.DataException
Message: Data exception
[...]
So far so normal, we stopped at the first exception that was thrown and we can have a look at that exception with !pe
.
If we switch to another thread, we can see that the exception is indicated with a #
in the list of threads, as long as it's not overwritten by the .
(current thread).
0:000> ~1s
0:001> ~
# 0 Id: 28a8.501c Suspend: 1 Teb: 00cc6000 Unfrozen
. 1 Id: 28a8.1044 Suspend: 1 Teb: 00cc9000 Unfrozen
[...]
Here's an interesting part: let's freeze thread 0 and run the application so that a second exception is thrown.
0:001> ~0f
0:001> g
System 0: 1 of 7 threads are frozen
WARNING: Continuing a non-continuable exception
System 0: 1 of 8 threads were frozen
System 0: 1 of 8 threads are frozen
(28a8.4228): CLR exception - code e0434352 (!!! second chance !!!)
System 0: 1 of 8 threads were frozen
[...]
Now we have another exception that caused the debugger to stop.
0:006> ~1s
[...]
0:001> ~
0 Id: 28a8.501c Suspend: 1 Teb: 00cc6000 Frozen
. 1 Id: 28a8.1044 Suspend: 1 Teb: 00cc9000 Unfrozen
2 Id: 28a8.1a2c Suspend: 1 Teb: 00ccc000 Unfrozen
3 Id: 28a8.5cfc Suspend: 1 Teb: 00ccf000 Unfrozen
4 Id: 28a8.490 Suspend: 1 Teb: 00cd2000 Unfrozen
5 Id: 28a8.2b60 Suspend: 1 Teb: 00cd5000 Unfrozen
# 6 Id: 28a8.4228 Suspend: 1 Teb: 00cd8000 Unfrozen
[...]
That exception happened on thread 6. We can also see that we only have one #
mark in that list, not two.
On the correct thread, we can print the exception:
0:006> !pe
Exception object: 02eb3ff4
Exception type: System.Configuration.ConfigurationException
Message: Config exception
[...]
On the wrong thread, we can't:
0:006> ~1s
[...]
0:001> !pe
The current thread is unmanaged
Lesson learned: the !pe
command is thread sensitive.
Now, what about the other two exceptions, A...
and B...
? We can find them on the heap:
0:000> !dumpheap -type BadImageFormatException
Address MT Size
02eb2a6c 6e3983c4 92
[...]
Fields:
MT Field Offset Type VT Attr Value Name
[...]
6e342734 40002ab 20 System.Object 0 instance 00000000 _stackTrace
[...]
The exception that was not thrown at all, does not have a stack trace. It's null
.
0:000> !dumpheap -type ApplicationException
Address MT Size
02eb2ae4 6e388090 84
Statistics:
MT Count TotalSize Class Name
6e388090 1 84 System.ApplicationException
Total 1 objects
0:000> !DumpObj /d 02eb2ae4
Name: System.ApplicationException
[...]
Fields:
MT Field Offset Type VT Attr Value Name
[...]
6e342734 40002ab 20 System.Object 0 instance 02eb2b7c _stackTrace
[...]
The exception that was thrown but caught, still has its stack trace.
0:000> !pe 02eb2ae4
Exception object: 02eb2ae4
Exception type: System.ApplicationException
Message: An exception
InnerException: <none>
StackTrace (generated):
SP IP Function
00EFEEA0 052F08D2 ConsoleNetFramework!ConsoleNetFramework.Program.Main()+0x8a
StackTraceString: <none>
HResult: 80131600
Lesson learned: !pe
can take an arbitrary exception as parameter and print the exception with its call stack.
Looking at the output of the managed !threads
, both exceptions will be listed (unlike ~
which shows only one #
):
0:001> !threads
ThreadCount: 3
UnstartedThread: 0
BackgroundThread: 1
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
Lock
ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception
0 1 501c 00fb99c0 2a020 Preemptive 02EC0714:00000000 00f815a0 0 MTA System.Data.DataException 02eb2ca8
5 2 2b60 00fc4728 2b220 Preemptive 00000000:00000000 00f815a0 0 MTA (Finalizer)
6 3 4228 00fec9a0 2b020 Preemptive 02EC5B70:00000000 00f815a0 0 MTA System.Configuration.ConfigurationException 02eb3ff4
what steps can I take to find out the origin of NullReferenceException?
With the call stack and symbols you should be able to identify a single line of code. Next step is to do a code review there. Figure out which variable is null
. Write a unit test to reproduce the issue. Then fix the bug. Like in red/green refactoring.
Related Topics
How to Get Rendered HTML (Processed by JavaScript) in Webbrowser Control
Automatically Set Appsettings.JSON for Dev and Release Environments in ASP.NET Core
How to Get All Classes Within a Namespace
Backgroundworker Runworkercompleted Event
Ignore Mapping One Property with Automapper
C#: Raising an Inherited Event
Getfiles with Multiple Extensions
Are Static Class Instances Unique to a Request or a Server in ASP.NET
Nullable Type Issue with : Conditional Operator
Differencebetween a Mutable and Immutable String in C#
Why Does Boolean.Tostring Output "True" and Not "True"
How to Use a String to Create a Ef Order by Expression
Comparing Two Strings, Ignoring Case in C#
Does .Net Have a Way to Check If List a Contains All Items in List B
How to Parse a Month Name (String) to an Integer for Comparison in C#