当您在 Java 中使用 RMI 时,异常的远程堆栈跟踪将在您收到它时添加到前面,有点像这样:
ERROR Client received error when doing stuff:
myapp.FooBarException: bla
at server.myMethod()
at rmi.callHandler() // and now, on the next line comes the client
at rmi.sendCall();
at client.doServerMethod()
at Thread.run()
这种堆栈跟踪“伪造”是如何完成的?
我要它做什么(除了被迭代)?好吧,如果我能做到这一点,它会对我有帮助:
outer() {
thread = new Thread(...
inner();
// inner() throws
// RuntimeException
// at inner();
// at Runnable.run();
// at Thread.run();
// at outer();
// at lalalala();
// ...
).start();
thread.join();
}
并使 inner()
中抛出的异常在堆栈跟踪中也有 outer()
(和链下的方法),用于日志记录目的。
最佳答案
这有点简单:
Throwable 有方法 getStackTrace()
和 setStackTrace()
。
来自 one of my projects (非开源,但也许有一天我会打开远程调用引擎):
/**
* Setzt den Stack-Trace zusammen. Das untere Ende (tiefer in der
* Aufrufhierarchie, am Anfang des Arrays/der Ausgabe) ist das,
* welches im Throwable schon drin ist, das obere Ende wird aus
* dem aktuellen Stack genommen. Dazwischen
* kommt ein "Remote-Aufruf-Markierer".
*/
为方便起见翻译:
Merges the stack trace. The lower end (deeper in the call hierarchy, at the end of the array/the output) is what already is in the stack, the upper end will be taken from the current stack. Between them we will put an Remote call marker.
private void mergeStackTraces(Throwable error)
{
StackTraceElement[] currentStack =
new Throwable().getStackTrace();
int currentStackLimit = 5; // TODO: raussuchen
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: Das Passwort für Nutzer »Paul« ist falsch.
at de.fencing_game.db.userdb.Db4oUserDB.login(Db4oUserDB.java:304)
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)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:226)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:647)
at java.awt.EventQueue.access$000(EventQueue.java:96)
at java.awt.EventQueue$1.run(EventQueue.java:608)
at java.awt.EventQueue$1.run(EventQueue.java:606)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:105)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:617)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:275)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:200)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:185)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:177)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:138)
我想 RMI 系统做的事情非常相似(只是没有 ══════════════════════════
) .
编辑: 对于您的用例,您必须在启动内部线程时保存外部线程的堆栈跟踪,然后在 run 方法中捕获异常并将外部堆栈跟踪附加到内部异常的堆栈跟踪。不过,我真的建议放置某种类型的分隔符。
关于java - 在 Java 中伪造堆栈跟踪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6270256/