-
Bug
-
Resolution: Fixed
-
Minor
-
None
For a long time, remoting has a way to decorate received exception will a "call side" stacktrace but that is just pain to navigate even with decent application knowledge (one tells local and remote stack frames apart based on the classes involved rather then the way exception is presented). Putting aside fiddling with stacktraces the way Channel.attachCallSiteStackTrace does is dangerous at best. In Java 9 code will need to be further complicated or module information will be thrown away. Here is how it looks like now:
java.io.IOException: Local nested at hudson.remoting.ChannelTest.testCallSiteStacktrace(ChannelTest.java:191) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at junit.framework.TestCase.runTest(TestCase.java:176) at junit.framework.TestCase.runBare(TestCase.java:141) at junit.framework.TestResult$1.protect(TestResult.java:122) at junit.framework.TestResult.runProtected(TestResult.java:142) at junit.framework.TestResult.run(TestResult.java:125) at junit.framework.TestCase.run(TestCase.java:129) at junit.framework.TestSuite.runTest(TestSuite.java:252) at junit.framework.TestSuite.run(TestSuite.java:247) at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:86) at org.apache.maven.surefire.junit4.JUnit4Provider.executeFailedMethod(JUnit4Provider.java:381) at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:292) at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238) at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:161) at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:290) at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:242) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:121) Caused by: java.io.IOException: Node nested at hudson.remoting.ChannelTest$ThrowingCallable.call(ChannelTest.java:197) at hudson.remoting.ChannelTest$ThrowingCallable.call(ChannelTest.java:195) at hudson.remoting.UserRequest.perform(UserRequest.java:203) at hudson.remoting.UserRequest.perform(UserRequest.java:52) at hudson.remoting.Request$2.run(Request.java:356) at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:68) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) at ......remote call to north(Native Method) at hudson.remoting.Channel.attachCallSiteStackTrace(Channel.java:1647) at hudson.remoting.UserResponse.retrieve(UserRequest.java:303) at hudson.remoting.Channel.call(Channel.java:896) at hudson.remoting.ChannelTest.testCallSiteStacktrace(ChannelTest.java:189) ... 20 more Caused by: java.io.IOException: Node says hello! at hudson.remoting.ChannelTest$ThrowingCallable.call(ChannelTest.java:197) at hudson.remoting.ChannelTest$ThrowingCallable.call(ChannelTest.java:195) at hudson.remoting.UserRequest.perform(UserRequest.java:203) at hudson.remoting.UserRequest.perform(UserRequest.java:52) at hudson.remoting.Request$2.run(Request.java:356) at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:68) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)
Proposal #1: Suppressed exception.
Well, it is not a suppressed exception but it is trivial to implement and there is so little to go wrong about it. Stacktraces are untouched and the top-level exception coming from the other side has the call-site attached. The call side stacktrace is complete and clearly separated but it still requires some training to identify what is going on.
java.io.IOException: Local nested at hudson.remoting.ChannelTest.testCallSiteStacktrace(ChannelTest.java:191) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at junit.framework.TestCase.runTest(TestCase.java:176) at junit.framework.TestCase.runBare(TestCase.java:141) at junit.framework.TestResult$1.protect(TestResult.java:122) at junit.framework.TestResult.runProtected(TestResult.java:142) at junit.framework.TestResult.run(TestResult.java:125) at junit.framework.TestCase.run(TestCase.java:129) at junit.framework.TestSuite.runTest(TestSuite.java:252) at junit.framework.TestSuite.run(TestSuite.java:247) at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:86) at org.apache.maven.surefire.junit4.JUnit4Provider.executeFailedMethod(JUnit4Provider.java:381) at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:292) at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238) at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:161) at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:290) at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:242) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:121) Caused by: java.io.IOException: Node nested at hudson.remoting.ChannelTest$ThrowingCallable.call(ChannelTest.java:197) at hudson.remoting.ChannelTest$ThrowingCallable.call(ChannelTest.java:195) at hudson.remoting.UserRequest.perform(UserRequest.java:203) at hudson.remoting.UserRequest.perform(UserRequest.java:52) at hudson.remoting.Request$2.run(Request.java:356) at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:68) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Suppressed: hudson.remoting.Channel$CallSiteStackTrace: Remote call to north at hudson.remoting.Channel.attachCallSiteStackTrace(Channel.java:1647) at hudson.remoting.UserResponse.retrieve(UserRequest.java:303) at hudson.remoting.Channel.call(Channel.java:896) at hudson.remoting.ChannelTest.testCallSiteStacktrace(ChannelTest.java:189) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at junit.framework.TestCase.runTest(TestCase.java:176) at junit.framework.TestCase.runBare(TestCase.java:141) at junit.framework.TestResult$1.protect(TestResult.java:122) at junit.framework.TestResult.runProtected(TestResult.java:142) at junit.framework.TestResult.run(TestResult.java:125) at junit.framework.TestCase.run(TestCase.java:129) at junit.framework.TestSuite.runTest(TestSuite.java:252) at junit.framework.TestSuite.run(TestSuite.java:247) at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:86) at org.apache.maven.surefire.junit4.JUnit4Provider.executeFailedMethod(JUnit4Provider.java:381) at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:292) at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238) at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:161) at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:290) at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:242) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:121) Caused by: java.io.IOException: Node says hello! ... 10 more
Proposal #2: Prefix stackframes with channel destination name if remote.
This can be combined with existing approach and #1 to signify which exception (trace element) is coming from each side but it does require tempering with {{StackTraceElement}}s.
Proposal #3: Update remote exception message with text indicating those are remote.
Can be combined approach and #1. Requires reflection to work correctly. Might not have effect for certain exception types.
Note sure what other ways there are but my preferred approach is #1.
jglick,stephenconnolly,oleg_nenashev, thoughts?