2011-04-15 9 views
3

これは可能ですか?スタックトレースに特定のクラスタイプが含まれないように例外をスローする

問題は、巨大なアプリケーションには、例えばサーブレットフィルタがたくさんあることです。そして、HTTPリクエストに関してスローされた各例外は、160行がcatalina/tomcatスタックからのものであれば250行を含みますが、これは絶対に重要ではありません。

250行のスタックトレースを持つことは非常に困難です。

答えて

7

はい、スタックトレースを操作することは可能です。言われているように、それはあなたがどこに問題を攻撃したいか(そしてできるか)によって決まります。一例として、


:私たちはターゲット側でそれをキャッチした例外の場合には、私たちのプロジェクトのために実装されたリモートメソッド呼び出しプロトコルの場合

は、(下のいくつかの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として設定することをお勧めします。原因(リンクされたスローアブル)についてもこれを行うようにしてください。

例外のコンストラクタ、またはスタックトレースを印刷する場所、またはその間のどこか(例外を捕捉し、操作し、再実行する場所)でこれを行うことができます。

2

行を読み込み、特定の正規表現に一致するものを排除する出力ストリームを作成することができます。

次に、Exception.printStackTrace(YourFilteredOutputStream)を使用します。

log4jを使用している場合は、これを行うAppenderを作成できます。架空のAppender使用

Log4jの構成(Examples)

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

あなたがキャッチ例外のためのあなたのスタックトレースからエントリを削除することができます。例外に対してprintStackTraceをオーバーライドすることができます。カスタムロガーを作成して、特定の行を無視することもできます。あなたがコントロールしているものによって大きく異なります。

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); 
+0

これはまだフィルタリングを逃しています:-p –

+0

@Paulo、私はコードでそれを逃していました - 今修正。 –

0

これはちょっと古い投稿ですが、Log4JまたはSL4Jを使用する場合は、必要な項目のみを表示するようにプロパティを設定できます。それは非常に柔軟です。

関連する問題