Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Throwing exceptions so that stack trace doesn't contain certain class types

Is it possible to do this ?

The problem is, that huge applications have tons of servlet filters for instance. And each exception that is thrown regarding http request contains 250 lines when 160 of them is from catalina/tomcat stack, which is absolutely not important.

And having 250 lines long stack traces is very hard to work with.

like image 450
lisak Avatar asked Dec 04 '22 22:12

lisak


1 Answers

Yes, it is possible to manipulate the stack trace. As said, it depends on where you want to (and can) attack the problem.


As an example:

For a remote method-call protocol I implemented for our project, in the case of an exception we catch it at the target side, cut off the lower some StackTraceElements (which are always the same, until the actual calling of the target method with reflection), and send the exception with the important part of the stack trace to the caller side.

There I reconstruct the exception with its (sent) stack trace, and then merge it with the current Stack trace. For this, we also remove the top some elements of the current stack trace (which contain only calls of the remote-call framework):

    private void mergeStackTraces(Throwable error)
    {
        StackTraceElement[] currentStack =
            new Throwable().getStackTrace();
        int currentStackLimit = 4; // TODO: raussuchen

        // We simply cut off the top 4 elements, which is just 
        // right for our framework. A more stable solution
        // would be to filter by class name or such.

        StackTraceElement[] oldStack =
            error.getStackTrace();
        StackTraceElement[] zusammen =
            new StackTraceElement[currentStack.length - currentStackLimit +
                                  oldStack.length + 1];
        System.arraycopy(oldStack, 0, zusammen, 0, oldStack.length);
        zusammen[oldStack.length] =
            new StackTraceElement("══════════════════════════",
                                  "<remote call %" +callID+ ">",
                                  "", -3);
        System.arraycopy(currentStack, currentStackLimit,
                         zusammen, oldStack.length+1,
                         currentStack.length - currentStackLimit);
        error.setStackTrace(zusammen);
    }

This gives, for example, this trace printed:

java.lang.SecurityException: The user example does not exist 
    at de.fencing_game.db.userdb.Db4oUserDB.login(Db4oUserDB.java:306)
    at de.fencing_game.server.impl.StandardServers$SSServer$1.run(StandardServers.java:316)
    at de.fencing_game.server.impl.StandardServers$SSServer$1.run(StandardServers.java:314)
    at java.security.AccessController.doPrivileged(Native Method)
    at de.fencing_game.server.impl.StandardServers$SSServer.login(StandardServers.java:313)
    at de.fencing_game.transport.server.ServerTransport$ConnectionInfo$4.login(ServerTransport.java:460)
    at ══════════════════════════.<remote call %2>()
    at $Proxy1.login(Unknown Source)
    at de.fencing_game.gui.basics.LoginUtils.login(LoginUtils.java:80)
    at de.fencing_game.gui.Lobby.connectTo(Lobby.java:302)
    at de.fencing_game.gui.Lobby$20.run(Lobby.java:849)

Of course, for your case you would better simply iterate through your array, copy the important elements into a list, and then set this as the new stackTrace. Make sure to do this for the causes (i.e. linked throwables), too.

You can do this in the constructor of your exceptions, or where you print the stack traces, or anywhere between (where you catch, manipulate and rethrow the exception).

like image 101
Paŭlo Ebermann Avatar answered Dec 07 '22 12:12

Paŭlo Ebermann