有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

有可能这样做吗

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

拥有250行长的堆栈跟踪是非常困难的


共 (5) 个答案

  1. # 1 楼答案

    我同情。 隐藏不需要的StackTraceElements并生成自己的stacktrace输出怎么样

    比如:

    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 楼答案

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

    然后使用异常。printStackTrace(您的过滤器输出流)

    如果您使用的是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. # 3 楼答案

    对于捕获的异常,可以从堆栈跟踪中删除条目。您可以覆盖例外的printStackTrace。您还可以创建一个自定义记录器来忽略某些行。这在很大程度上取决于你能控制什么

  4. # 4 楼答案

    这有点过时,但无论如何,如果使用Log4J或SL4J,可以将属性设置为仅显示所需的项目。它很灵活

  5. # 5 楼答案

    是的,可以操纵堆栈跟踪。如前所述,这取决于你想(并且能够)解决问题的地方


    例如:

    对于我为我们的项目实现的远程方法调用协议,如果出现异常,我们在目标端捕获它,切断较低的一些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。也要确保这样做的原因(即链接的一次性物品)

    您可以在异常的构造函数中,或者在打印堆栈跟踪的地方,或者在两者之间的任何地方(捕捉、操作和重新显示异常的地方)执行此操作