4 Stimmen

Auslösen von Ausnahmen, so dass die Stapelverfolgung bestimmte Klassentypen nicht enthält

Ist es möglich, dies zu tun?

Das Problem ist, dass große Anwendungen zum Beispiel viele Servlet-Filter haben. Und jede Ausnahme, die in Bezug auf http-Anforderung geworfen wird, enthält 250 Zeilen, wenn 160 von ihnen von Catalina/Tomcat Stack, die absolut nicht wichtig ist.

Und 250 Zeilen lange Stack Traces sind sehr schwer zu verarbeiten.

9voto

Paŭlo Ebermann Punkte 70779

Ja, es ist möglich, den Stack-Trace zu manipulieren. Wie gesagt, es hängt davon ab, wo Sie das Problem angreifen wollen (und können).


Ein Beispiel:

Bei einem Protokoll für entfernte Methodenaufrufe, das ich für unser Projekt implementiert habe, fangen wir im Falle einer Exception diese auf der Zielseite ab, schneiden die unteren StackTraceElemente ab (die immer gleich sind, bis zum eigentlichen Aufruf der Zielmethode mit Reflection), und senden die Exception mit dem wichtigen Teil des Stack Trace an die Aufruferseite.

Dort rekonstruiere ich die Exception mit ihrem (gesendeten) Stacktrace, und füge ihn dann mit dem aktuellen Stacktrace zusammen. Dazu entfernen wir auch die obersten Elemente des aktuellen Stacktrace (die nur Aufrufe des Remote-Call-Frameworks enthalten):

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

Das ergibt zum Beispiel diese gedruckte Spur:

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)

In Ihrem Fall wäre es natürlich besser, wenn Sie einfach Ihr Array durchlaufen, die wichtigen Elemente in eine Liste kopieren und diese dann als neue stackTrace festlegen. Stellen Sie sicher, dass Sie dies auch für die Ursachen (d.h. verknüpfte Throwables) tun.

Sie können dies im Konstruktor Ihrer Ausnahmen tun, oder dort, wo Sie die Stack Traces ausgeben, oder irgendwo dazwischen (wo Sie die Ausnahme abfangen, manipulieren und erneut auslösen).

3voto

Dilum Ranatunga Punkte 13094

Ich kann das nachempfinden. Wie wäre es, die unerwünschten StackTraceElements auszublenden und eine eigene Stacktrace-Ausgabe zu erzeugen?

Etwa so:

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

Sie können Code wie diesen in einem benutzerdefinierten Logger verwenden. Sie können ihn auch verwenden, um nicht abgefangene Ausnahmen zu protokollieren:

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

2voto

Chris K Punkte 11536

Sie könnten einen Ausgabestrom erstellen, der Zeilen einliest und diejenigen eliminiert, die einer bestimmten Regex entsprechen.

Verwenden Sie dann Exception.printStackTrace( YourFilteredOutputStream );

Wenn Sie log4j verwenden, könnten Sie einen Appender schreiben, der dies tut.

Log4j-Konfiguration (Beispiele) unter Verwendung eines hypothetischen Absender :

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

Ich würde wahrscheinlich die Unterklasse 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); 
   }
}

2voto

Peter Lawrey Punkte 511323

Sie können Einträge für eine abgefangene Exception aus Ihrem Stacktrace entfernen. Sie können printStackTrace für Ihre Ausnahmen außer Kraft setzen. Sie können auch einen eigenen Logger erstellen, um bestimmte Zeilen zu ignorieren. Vieles hängt davon ab, worüber Sie die Kontrolle haben.

0voto

user991945 Punkte 103

Es ist ein etwas veralteter Beitrag, aber wenn Sie Log4J oder SL4J verwenden, können Sie die Eigenschaften so einstellen, dass nur die gewünschten Elemente angezeigt werden. Das ist ziemlich flexibel.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X