Создание исключений, чтобы трассировка стека не содержала определенные типы классов - PullRequest
4 голосов
/ 15 апреля 2011

Возможно ли это сделать?

Проблема в том, что огромные приложения имеют, например, тонны фильтров сервлетов. И каждое исключение, которое выдается в отношении http-запроса, содержит 250 строк, когда 160 из них относятся к стеку catalina / tomcat, что абсолютно не важно.

А с трассировкой стека длиной 250 строк работать очень сложно.

Ответы [ 5 ]

8 голосов
/ 16 апреля 2011

Да, можно манипулировать трассировкой стека.Как уже говорилось, это зависит от того, где вы хотите (и можете) атаковать проблему.


Например:

Для протокола удаленного вызова метода, который я реализовал для нашего проекта,в случае исключения мы перехватываем его на целевой стороне, обрезаем несколько нижних 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.Удостоверьтесь, что вы делаете это и для причин (т. Е. Связанных метаний).

Вы можете сделать это в конструкторе ваших исключений, или там, где вы печатаете трассировки стека, или где-нибудь между (где вы ловите, манипулируетеи отбросить исключение).

3 голосов
/ 15 апреля 2011

Я сочувствую. Как насчет сокрытия нежелательных 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 голосов
/ 15 апреля 2011

Вы можете удалить записи из вашей трассировки стека для исключений, которые вы ловите.Вы можете переопределить printStackTrace для ваших исключений.Вы также можете создать собственный регистратор, чтобы игнорировать определенные строки.Многое зависит от того, что вы контролируете.

2 голосов
/ 15 апреля 2011

Вы можете создать выходной поток, который будет читать строки и исключать те, которые соответствуют определенному регулярному выражению.

Затем используйте Exception.printStackTrace (YourFilteredOutputStream);

Если вы используете log4j, вы можете написать Appender, который сделает это.

Конфигурация Log4j (Примеры) с использованием гипотетического 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); 
   }
}
0 голосов
/ 06 сентября 2014

Это что-то вроде устаревшего поста, но если вы используете Log4J или SL4J, вы можете установить в свойствах только те элементы, которые вам нужны.Это довольно гибкий.

...