是否可以這樣做?拋出異常,以便堆棧跟蹤不包含某些類的類型
問題是,巨大的應用程序有很多servlet過濾器。並且,有關http請求的每個異常都包含250行,其中160行來自catalina/tomcat堆棧,這絕對不重要。
並且有250行長的堆棧痕跡很難使用。
是否可以這樣做?拋出異常,以便堆棧跟蹤不包含某些類的類型
問題是,巨大的應用程序有很多servlet過濾器。並且,有關http請求的每個異常都包含250行,其中160行來自catalina/tomcat堆棧,這絕對不重要。
並且有250行長的堆棧痕跡很難使用。
是的,可以操縱堆棧跟蹤。如上所述,這取決於你想要(並且可以)攻擊問題的位置。
作爲一個例子:
對於遠程方法調用協議我實現爲我們的項目,在我們捕獲它在目標側的異常的情況下,切斷下部一些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),也一樣。
您可以在異常的構造函數中,或者打印堆棧軌跡的位置,或者在捕捉,操作和重新拋出異常的地方之間的任何地方執行此操作。
您可以創建一個讀取行的輸出流,並刪除與特定正則表達式匹配的輸出流。
然後使用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);
}
}
您可以從您的堆棧跟蹤刪除條目爲您捕捉異常。您可以爲您的例外覆蓋printStackTrace。您還可以創建自定義記錄器來忽略某些行。很大程度上取決於你的控制權。
我同情。 如何隱藏不需要的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);
這是有點過時的帖子,但對於它的價值,如果你使用Log4J或SL4J,你可以設置屬性來只顯示你想要的項目。它非常靈活。
這仍然錯過了過濾,雖然:-p – 2011-04-15 19:37:34