PDA

View Full Version : Exception stack trace


Matthew R
03-30-2006, 03:26 AM
I'd like to use AOP for logging exceptions. However, when a target object throws an exception, the exception that I receive within both the advice method and the calling code has lost the original stack trace. The stack trace is an important piece of information to log for debugging purposes... Is there any way to get the original exception before it is re-thrown and the stack trace is recreated?

Thanks,
Matthew

Aleks Seovic
03-31-2006, 06:33 AM
Hi Matthew,

Which advice type are you using for your logging advice?

- Aleks

Matthew R
04-03-2006, 10:00 PM
Which advice type are you using for your logging advice?

Hi Aleks,

I tried both IMethodInterceptor and IThrowsAdvice. For this case, I decided to switch to Castle.DynamicProxy, since it uses delegates instead of reflection to call the target method. As a result, the exception is of the expected type rather than TargetInvocationException, without the need to get the inner exception and re-throw it.

Thanks,
Matthew

illianj
04-19-2006, 08:09 PM
I've been struggling with this same problem for awhile now. Basically, I can't get Spring to let me see the original stack trace if I'm using AOP.

I'm more or less built exactly like the example out of the documentation. Specifically:
public void AfterThrowing(MethodInfo method, Object[] args, Object target, Exception ex)
{
Console.Writeline(ex);
}


And no matter what I try, I end up with the following stack trace:

at Spring.Aop.Framework.AbstractMethodInvocation.Invo keJoinpoint()
at Spring.Aop.Framework.AbstractMethodInvocation.Proc eed()
at Spring.Aop.Framework.Adapter.ThrowsAdviceIntercept or.Invoke(IMethodInvocation invocation)

illianj
04-19-2006, 08:51 PM
I was able to solve my problem, but it required downloading and modifying the source Spring code. I borrowed the fix from Chris Taylor at:

http://dotnetjunkies.com/WebLog/chris.taylor/archive/2004/03/03/8353.aspx

I modified the class AbstractMethodInvocation.cs and changed the mehod InvokeJoinpoint to be the following:

protected internal virtual object InvokeJoinpoint()
{
object returnValue = null;
try
{
returnValue = Method.Invoke(target, arguments);
}
catch (TargetInvocationException ex)
{
// NB: Error checking etc. excluded
// Get the _remoteStackTraceString of the Exception class
FieldInfo remoteStackTraceString = typeof(Exception).GetField("_remoteStackTraceString",
BindingFlags.Instance | BindingFlags.NonPublic);

// Set the InnerException._remoteStackTraceString to the current InnerException.StackTrace
remoteStackTraceString.SetValue(ex.InnerException,
ex.InnerException.StackTrace + Environment.NewLine);

throw ex.InnerException;
}
return returnValue;
}

And now I get the results I was looking for.

.ben
04-20-2006, 09:25 AM
Is this "the" way to go? I'm having the same issue.

Mark Pollack
04-24-2006, 12:27 AM
Hi,
I'm looking into this. The solution shown will preserve the information in the string of the stacktrace but the information really isn't in the exception in the sense of its StackFrames. It is using the "remoteStackTraceString" as a placeholder for this infomation which seems "bad" because there could be information that needs to be preserved there as well. (One could append instead of overwrite I guess. If invoking via a delegate works then that maybe the way to go. I'll post back when I have a more definitive answer.
Cheers,
Mark

Mark Pollack
04-24-2006, 02:41 AM
Hi guys,

I've made a JIRA issue (http://opensource.atlassian.com/projects/spring/browse/SPRNET-312) to keep track of this. Thanks for pointing it out and suggesting a solution.

Cheers,
Mark

Bruno Baia
05-05-2006, 12:15 AM
Hi,

fixed with the code provided by illianj.
We'll stick with it until Spring.Aop refactoring...

Later,
Bruno

Jay13mhsc
06-13-2008, 02:05 PM
There's the same problem with the ThrowsAdviceInterceptor : you always loose the original stack trace !
I've found the bug !
Here's the code !

public object Invoke(IMethodInvocation invocation)
{
try
{
return invocation.Proceed();
}
catch (TargetInvocationException ex)
{
// bah, this is a tad gross...
Exception realException = ex.InnerException;
LookupAndInvokeAnyHandler(realException, invocation);
throw realException;
}
catch (Exception ex)
{
LookupAndInvokeAnyHandler(ex, invocation);
//throw ex; : not very good in .Net !! ;)
throw;
}
}

I tried this and it effectively works !
I've also searched all troubles like this in the spring source, and it's plainty of it !
In .net, if you catch an exception, that you call 'ex', and you rethrow it with throw ex;, you will loose all your stack trace, and it will be rebuild from where this instruction is.
If you want to be sure that your stack trace is not altered, just use throw; !!

Hope this helps ! ;)

Bruno Baia
06-23-2008, 08:26 AM
Fixed.

Thanks !

- Bruno

Schenka7
07-30-2008, 12:16 PM
Hi, I have the same problem,

I tried to solve it like Jay13 proposed but it didn't work for me.
The Stack Trace ist still starting from the Proxy call.

An Example:
ScannerInterface.ScannerException: An error Occured
at ScannerOPN.OPN2001.GetParam(Int32 param) in C:\Dokumente und Einstellungen\Berenstein.IDENTWERK\Eigene Dateien\Visual Studio 2005\Projects\InterfaceTestOPN\ScannerOPN\OPN2001. vb:Line 148.
at Spring.DynamicReflection.Method_GetParam_7ce1ffa33 61f4297a1c8d9837ec38f40.Invoke(Object target, Object[] args)
at Spring.Reflection.Dynamic.SafeMethod.Invoke(Object target, Object[] arguments)
at Spring.Aop.Framework.DynamicMethodInvocation.Invok eJoinpoint()
at Spring.Aop.Framework.AbstractMethodInvocation.Proc eed()
at Spring.Aop.Framework.Adapter.ThrowsAdviceIntercept or.Invoke(IMethodInvocation invocation)


BTW: I have the latest revision of Spring.NET in use.

Does anyone knows a solution?

thanks

CyberPunk
07-30-2008, 04:42 PM
There's the same problem with the ThrowsAdviceInterceptor : you always loose the original stack trace !
I've found the bug !
Here's the code !

public object Invoke(IMethodInvocation invocation)
{
try
{
return invocation.Proceed();
}
catch (TargetInvocationException ex)
{
// bah, this is a tad gross...
Exception realException = ex.InnerException;
LookupAndInvokeAnyHandler(realException, invocation);
throw realException;
}
catch (Exception ex)
{
LookupAndInvokeAnyHandler(ex, invocation);
//throw ex; : not very good in .Net !! ;)
throw;
}
}

I tried this and it effectively works !
I've also searched all troubles like this in the spring source, and it's plainty of it !
In .net, if you catch an exception, that you call 'ex', and you rethrow it with throw ex;, you will loose all your stack trace, and it will be rebuild from where this instruction is.
If you want to be sure that your stack trace is not altered, just use throw; !!

Hope this helps ! ;)

I might be mistaken but this is documented in MSDN.

When you do a "throw ex" you need to keep in mind that ex is a local variable created in the scope of the catch, so the stack trace will start from there upwards. If you do exception translation, you need to set ex.InnerException=YourOriginalException.

Whenever you just do a "throw" you are just passing the bucket, so the runtime actually does the job of keeping track of the full exception stack trace.

Bruno Baia
07-30-2008, 10:49 PM
Hi,

The fix have been committed some time ago.
Please wait for the next release (1.2) or download one of the latest builds.


- Bruno

Schenka7
08-04-2008, 08:13 AM
Thank you Bruno, I thought it has been fixed already in the actual release.