抛出异常,以便堆栈跟踪不包含某些类类型

时间:2011-04-15 16:18:45

标签: java exception-handling stack-trace

是否可以这样做?

问题是,巨大的应用程序有大量的servlet过滤器。并且关于http请求抛出的每个异常包含250行,其中160个来自catalina / tomcat堆栈,这绝对不重要。

拥有250行长的堆栈跟踪非常难以使用。

5 个答案:

答案 0 :(得分:8)

是的,可以操纵堆栈跟踪。如上所述,这取决于你想要(并且可以)攻击问题的位置。


举个例子:

对于我为我们的项目实现的远程方法调用协议,在异常情况下我们在目标端捕获它,切断一些StackTraceElements(它们总是相同的,直到实际调用目标)带反射的方法),并将带有堆栈跟踪重要部分的异常发送给调用方。

我用其(已发送)堆栈跟踪重构异常,然后将其与当前堆栈跟踪合并。 为此,我们还删除了当前堆栈跟踪的顶部一些元素(仅包含远程调用框架的调用):

    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);
    }

这样就可以打印出这条痕迹:

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)

当然,对于您的情况,您最好简单地遍历数组,将重要元素复制到列表中,然后将其设置为新的stackTrace。确保为原因(即链接的throwables)执行此操作。

您可以在异常的构造函数中执行此操作,也可以在打印堆栈跟踪的位置执行此操作,也可以在(捕获,操作和重新抛出异常的位置)之间的任何位置执行此操作。

答案 1 :(得分:3)

我同情。 如何隐藏不需要的StackTraceElements,并生成自己的堆栈跟踪输出?

这样的事情:

Set<String> hideClassNames = ....;
...
void print(Throwable t, PrintStream out) {
  for (Throwable c = e; c != null; ) {
    for (StackTraceElement e : c.getStackTrace()) {
      if (!hideClassNames.contains(e.getClassName())) {
        out.println(e.getClassName() + 
                    "." + e.getMethodName() + 
                    " ( " + e.getFileName() +
                    ":" + e.getLineNumber()) + ")";
      }
    }
    c = c.getCause();
    if (c != null) {
      out.println("Caused by");
    }
}

您可以在自定义记录器中使用这样的代码。您还可以使用它来记录未捕获的异常:

Thread.UncaughtExceptionHandler handler = new Thread.UncaughtExceptionHandler() {
  public void uncaughtException(Thread t, Throwable e) {
    print(t, System.err);
  }
};
Thread.setDefaultUncaughtExceptionHandler(handler);

答案 2 :(得分:2)

您可以创建一个读取行的输出流,并删除与特定正则表达式匹配的输出流。

然后使用Exception.printStackTrace(YourFilteredOutputStream);

如果您正在使用log4j,您可以编写一个执行此操作的Appender。

Log4j配置(Examples)使用假设的Appender

    <appender name="TRACE" class="com.example.YourAppender">
            <layout class="org.apache.log4j.PatternLayout">
                    <param name="ConversionPattern" value="[%t] %-5p %c - %m%n" />
            </layout>
    </appender>

我,我可能会继承FileAppender:

public class YourAppender extends FileAppender { 
   public YourAppender(...) {  
      super(...); 
   }
   public void doAppend(LoggingEvent ev) { 
      String message = ev.getMessage();  // or ev.getRenderedMessage(); 

      // build new LoggingEvent 
      LoggingEvent newEv = new LoggingEvent( /* params from old loggingg event */ ); 
      super.doAppend(newEv); 
   }
}

答案 3 :(得分:2)

您可以从堆栈跟踪中删除您捕获的异常中的条目。您可以覆盖printStackTrace以查找异常。您还可以创建自定义记录器以忽略某些行。很多都取决于你控制的内容。

答案 4 :(得分:0)

这是一个过时的帖子,但是对于它的价值,如果你使用Log4J或SL4J,你可以设置属性只显示你想要的项目。它非常灵活。