Why does the high part of the stack (in Exception.StackTrace) gets truncated?
Let's see a simple example:
public void ExternalMethod()
{
InternalMethod();
}
public void InternalMethod()
{
try
{
throw new Exception();
}
catch(Exception ex)
{
// ex.StackTrace here doesn't contain ExternalMethod()!
}
}
It seems like this is "by design". But what are the reasons for such a strange design? It only makes debugging more complex, because in log messages I can't understand who called InternalMethod() and often this information is very necessary.
As for solutions (for those who don't know), there are 2 general solutions as I understand:
1) We can log static Environment.StackTrace property, which contains the whole stack (for example, starting at the hiest level (message queue) and ending at the deepest method in which exception occurs).
2) We have to catch and log exceptions on highest levels. When we need to catch exceptions on lower levels to do something, we need to rethrow (with "throw" statement in C#) it further up.
But the question is about reasons of such design.
Ok, now I see what your getting at... Sorry for my confusion on the inlining thing.
The 'stack' in a caught exception is only a delta from the currently executing catch block to where the exception was thrown. Conceptually this behavior is correct in that the Exception.StackTrack tells you where the exception occurred within the context of this try/catch block. This allows exception stacks to be forwarded across 'virtual' calls and still maintain accuracy. One classic example of this being done is .Net Remoting exceptions.
Thus if you want a complete stack report in the catch block you would add the current stack to the exception's stack as in the example below. The only problem is this can be more expensive.
private void InternalMethod()
{
try
{
ThrowSomething();
}
catch (Exception ex)
{
StackTrace currentStack = new StackTrace(1, true);
StackTrace exceptionStack = new StackTrace(ex, true);
string fullStackMessage = exceptionStack.ToString() + currentStack.ToString();
}
}
As csharptest said this is by design. The StackTrace stops at the try block. Further more there is no hook in the framework that is called when an exception is thrown.
So the best you can do is something along these lines, it its an absolute requirement to get full stack traces (store a full trace on exceptions creation):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.CompilerServices;
using System.Diagnostics;
namespace ConsoleApplication15 {
[global::System.Serializable]
public class SuperException : Exception {
private void SaveStack() {
fullTrace = Environment.StackTrace;
}
public SuperException() { SaveStack(); }
public SuperException(string message) : base(message) { SaveStack(); }
public SuperException(string message, Exception inner) : base(message, inner) { SaveStack(); }
protected SuperException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
private string fullTrace;
public override string StackTrace {
get {
return fullTrace;
}
}
}
class Program {
public void ExternalMethod() {
InternalMethod();
}
public void InternalMethod() {
try {
ThrowIt();
} catch (Exception ex) {
Console.WriteLine(ex.StackTrace);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
public void ThrowIt() {
throw new SuperException();
}
static void Main(string[] args) {
new Program().ExternalMethod();
Console.ReadKey();
}
}
}
Outputs:
at System.Environment.get_StackTrace()
at ConsoleApplication15.SuperException..ctor() in C:\Users\sam\Desktop\Source
\ConsoleApplication15\ConsoleApplication15\Program.cs:line 17
at ConsoleApplication15.Program.ThrowIt() in C:\Users\sam\Desktop\Source\Cons
oleApplication15\ConsoleApplication15\Program.cs:line 49
at ConsoleApplication15.Program.InternalMethod() in C:\Users\sam\Desktop\Sour
ce\ConsoleApplication15\ConsoleApplication15\Program.cs:line 41
at ConsoleApplication15.Program.Main(String[] args) in C:\Users\sam\Desktop\S
ource\ConsoleApplication15\ConsoleApplication15\Program.cs:line 55
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, C
ontextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
It is not possible to inject this behaviour into the existing System defined exceptions, but .Net has a rich infrastructure for wrapping exceptions and rethrowing so it should not be a huge deal.
I know that in a catch block if you do throw ex; it truncates the stack trace at that point. It's possible that it's "by design" for throw since just throw; doesn't truncate the stack in a catch. Same may be going on here since you're throwing a new exception.
What happens if you cause an actual exception (i.e. int i = 100/0;)? Is the stack trace still truncated?
This is often caused by the compiler optimizations.
You can decorate methods you do not want to inline by using the following attribute:
[MethodImpl(MethodImplOptions.NoInlining)]
public void ExternalMethod()
{
InternalMethod();
}
Related
I have the following scenario:
class Program
{
static void Main(string[] args)
{
try
{
using (new Foo())
{
throw new Exception("Inside using block");
}
}
catch (Exception e)
{
}
}
}
public class Foo : IDisposable
{
public void Dispose()
{
throw new Exception("Inside dispose");
}
}
Is it somehow possible, to get the thrown exception - "Inside using block" - in the Dispose method of Foo and make it an InnerException of the Exception Inside dispose?
Edit:
For example:
class Program
{
static void Main(string[] args)
{
try
{
using (var fi = new FileHandler())
{
//open the file
fi.Open();
//write to the file
fi.Write();
//excption occurs
throw new Exception("Inside using block");
fi.Close();
}
}
catch (Exception e)
{
//now I only have the exception from the dispose but not the exception that occured in the using block itself
//I know I could wrap the code inside the using in a try/catch itself, just asking if it is possible without 2 try/catches
}
}
}
public class FileHandler : IDisposable
{
public void Dispose()
{
//Close the file
//for some reason it fails with an exception
throw new Exception("Inside dispose");
}
}
Per the Framework Design Guidelines (Cwalina, Abrams), section 9.3:
AVOID throwing an exception from within Dispose(bool) except under critical situations where the containing process has been corrupted.
If Dispose could raise an exception, further finally block cleanup logic will not execute. To work around this, the user would need to wrap every call to Dispose (within their finally block!) in a try block, which leads to very complex cleanup handlers. If executing a Dispose(bool) method, never throw an exception if disposing is false.
Also from section 9.3:
AVOID making types finalizable. Carefully consider any case in which you think a finalizer is needed. There is a real cost associated with instances with finalizers, from both a performance and code complexity standpoint."
I want to overload the throw keyword to catch a class which inherits from Exception and to have it do some logging and other stuff before the actual throw. Is this possible? Or do I have to use a regular function?
I've tried:
public class cSilException : Exception
{
private string m_strMsg;
public override void throw(cSilException ex)
{
}
...
...
}
Register the event AppDomain.FirstChanceException. There you get all exceptions before the are actually thrown. In the event handler you can check for your exception and do the required logging.
No magic and no bad design.
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException;
DoBadThings();
}
private static void DoBadThings()
{
DoOneLevelBelow();
}
private static void DoOneLevelBelow()
{
for(int i=0;i<10;i++)
{
try
{
if (i == 5)
{
var invalidCast = (string)((object)i);
}
else
{
throw new InvalidTimeZoneException();
}
}
catch
{
}
}
}
static void CurrentDomain_FirstChanceException(object sender, System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e)
{
if( e.Exception is InvalidCastException)
{
LogInvalidCast((InvalidCastException)e.Exception);
}
}
private static void LogInvalidCast(InvalidCastException invalidCastException)
{
Console.WriteLine("Got Invalid cast: {0}", invalidCastException);
}
This will lead to:
Got invalid cast: System.InvalidCastException: The object of the type
"System.Int32" cannot be converted to "System.String". at
ThrowTest.Program.DoOneLevelBelow() in
d:\Media\Blog\ThrowTest\Program.cs:line 31.
Please note since you are getting the exception before the stack is unwound you will see only the method where it did happen but not the calling methods since the stack was not unwound yet.
If you want the complete call stack you can use Environment.StackTrace to get all stack frames.
What you want to do is add a constructor to your exception and do whatever you need to do within that constructor.
public class cSilException : Exception
{
//constructor
public cSilException()
{
// do stuff here
}
}
Your notion of "overloading the throw keyword" was quite, er, how to put it, psychedelic.
Of course, as many have pointed out, it is best to avoid doing this if your intention is to do things such as logging. Alois Kraus has posted another answer with a very good suggestion.
I wouldn't recommend logging anything inside the exception's constructor since it violates the single responsibility principle and is considered a bad design. Also, the fact that an exception was created doesn't necessarily mean it has been thrown, and besides, exceptions can be caught and rethrown - these things may lead to incorrect logging messages.
Instead, you can use an application-wide exception handler which will handle exceptions according to your predefined policy. For example, you can have a look at the Enterprise Library Exception Handling Block and specifically this section.
You can't overload throw it is an integral part of the language (not a member of a class)
If you want to handle a specific Exception you should catch that exception:
try
{
// your code, which throws some exceptions
}
catch(cSilException csEx)
{
// handle csEx
throw; // rethrow this exception
}
catch(Exception ex)
{
// handle all other exceptions
}
This code catches the special exception cSilExceptionin a different code block than all other exceptions.
Look for methods and members of Exception class. You can define constructor for cSilException like this
public cSilException(string message)
{
Message = message;
}
and than in catch (cSilException ex) do Console.WriteLine(ex.Message);
Currently I have a Exception helper Class
public class ExceptionHelper
{
public static void Catch(Action action)
{
try
{
action();
}
catch (Exception ex)
{
// log error and thorw
// Do what you want
}
}
}
This is used to wrap methods in other classes to catch and logs exceptions like this
public static class RepoManger1
{
public static void TestMethod(string something)
{
ExceptionHelper.Catch(() =>
{
Int32 testvar1 = 10;
Int32 testvar2 = 0;
Int32 testvar3 = testvar1 / testvar2;
});
}
}
I am thinking of converting this to an Attribute that can be defined on a class or method
so that i do not have to write this code on every method.
Any other approach can also be suggested for the same
Attributes are meant to provide extra information about a class or method, while, if I understood correctly, you would like methods with your attribute to be automatically wrapped in your exception handling code, which is not possible.
In my opinion, the best thing to do here would be something like this:
public class ExceptionHelper {
public static void ProcessException(Exception exc) {
// common exception handling code
// e.g. log error, but DO NOT throw
}
}
public static class RepoManger1 {
public static void TestMethod(string something) {
try {
// do something
} catch (Exception exc) {
ExceptionHelper.ProcessException(exc);
// if necessary, re-throw the exception HERE, so that
// people reading your code can see that the exception
// is being re-thrown
throw;
}
}
}
I think that this is much more readable than your previous approach (and of any possible solution involving attributes). When I look at this code, I immediately understand that you are catching an exception and doing something with it, in the other cases it would take a while to figure it out.
I am actually writing a library class which could be used by multiple classes. I am simplying the example so as to make a point. Lets say I have three classes: A, B and C:
public class B
{
public static string B_Method()
{
string bstr = String.Empty;
try
{
//Do Something
}
catch
{
//Do Something
}
return bstr;
}
B is the library class that I am writing. Now there are lets say two other classes say A and C:
public class A
{
public void A_Method()
{
string astr = B.B_Method();
}
}
public class C
{
public void C_Method()
{
string cstr = B.B_Method();
}
}
The question is regarding the exception handling. I want the respective method of the two classes A and B to handle the exception occuring in B_Method in their own different ways.
I looked for framework design pattern, but felt that was not useful.
The approach that I usually follow is this:
If my method can do something useful with the exception, I catch it and do that.
If not, I don't catch it and leave it up to calling code to deal with it.
The only places where I would put a "catch all" block, is at entry points in UI code (such as event handlers for button clicks and such), since not catching exceptions there might take the process down.
This also means that exception clauses should catch the specific exceptions that you can handle.
One approach that I sometimes see is to catch the exception, wrap it in a new exception type and throw that. While that offers you some traceability, I also feel that it removes some options in the exception handling in calling code, such as having specific catch clauses for different scenarios. In these cases you will instead need to have if-clauses inspecting the inner exception with is less readable in my eyes.
B is the library class that I am writing.
If you have control over B code, B should rethrow the exception caught:
public class B
{
public static string B_Method()
{
string bstr = String.Empty;
try
{
// Do Something
}
catch(Exception e)
{
// Do Something (Log the exception details)
throw;
}
return bstr;
}
}
I want the respective method of the two classes A and B to handle the exception occuring in B_Method in their own different ways.
Now, B can log the exception and A and C can handle the rethrown exception is their own way.
You can rethrow or just let throw the exception in B_Method and catch it in A and C classes.
public class A
{
public void A_Method()
{
try
{
string astr = B.B_Method();
}
catch(Exception ex)
{
//Handle it in A way
}
}
public class C
{
public void C_Method()
{
try
{
string astr = B.B_Method();
}
catch(Exception ex)
{
//Handle it in C way
}
}
I think Design Patterns don't really apply here.. It's just OO programming.
remove the try and catch block from class b
public static string B_Method()throws Exception{
boolean success=compute();
if(!success){
throw new Exception("an error occured");
}
}
private static boolean compute(){
return false;
}
A situation where a method tries to log a custom exception (custom exception class as code sample) causes a problem:
[Serializable]
public class CustomException : Exception
{
public CustomException() { }
public CustomException(string message) : base(message) { }
public CustomException(string message, Exception inner) : base(message, inner) { }
protected CustomException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}
Creating the exception:
CustomException ex = new CustomException("Here is a new custom exception! ");
LogError(ex);
Method logging the exceptions (custom and others!):
public static void LogError(Exception ex)
{
//Saving exception messages, inner exceptions etc
//...
}
In this case the ex.Stacktrace of the custom exception is null when logging it!
I believe the reason is that the logging method (which tries to be a general purpose method) takes a Exception object as parameter rather than CustomException (?). What is the correct way to create a logging method, as overloading it with different exception types does seem a bit counterintuitive?
I believe the reason is that the logging method (which tries to be a general purpose method) takes a Exception object as parameter rather than CustomException (?)
Incorrect. It's null since you have not actually thrown the exception, just created it.
The stacktrace is generated as the exception travels up the callstack. Throwing the exception in the same method as you catch it will only create one stack trace item.
You can use:
public static void LogError<T>(T exception)
{
// Serialize the exception here and write to log
}
Note that you can simply use any object here in compbination with a human readable serialization format (i.e. formatted Json). Then you can simply log the serialized representation of the object, where all public fields/properties will be preserved.
Note that you'll also need throw/catch for stacktrace to be constructed for you.
Throw the CustomException instance before logging it. The runtime will fill in the stacktrace info
Log exceptions in catch block
Check logging level and log only message or full exception information.
For example, we use extension methods for TraceSource to log exceptions:
public static void TraceException(this TraceSource traceSource, Exception ex)
{
traceSource.TraceException(string.Empty, ex);
}
public static void TraceException(this TraceSource traceSource, string comment, Exception ex)
{
if (!string.IsNullOrWhiteSpace(comment))
comment += "\r\n";
traceSource.TraceEvent(TraceEventType.Error, (int)TraceEventType.Error,
comment + "ExceptionType: {0} \r\n ExceptionMessage: {1}", ex.GetType(), ex.Message);
if (traceSource.Switch.Level == SourceLevels.Verbose ||
traceSource.Switch.Level == SourceLevels.All)
{
traceSource.TraceEvent(TraceEventType.Verbose, 0, ex.ToString());
}
}
Usage:
catch(Exception ex)
{
_log.TraceException(ex);
}