New UI checkbox enables user to capture stack trace of every 'exit' trace event. This is useful for troubleshooting like this: http://johnsrandommusings.tumblr.com/post/33371606685/javadbb

This commit is contained in:
Erik Ostermueller 2013-12-08 09:58:24 -06:00
parent e756ba0d84
commit 560fa99eed
10 changed files with 177 additions and 4 deletions

Binary file not shown.

View File

@ -12,6 +12,7 @@ public class ClientStrings
public static final String ENABLE_BRANCH_TRACE = "Branch";
public static final String ENABLE_ARGS_TRACE = "Method Args, Return Values, Exceptions";
public static final String ENABLE_ARRAY_TRACE = "Truncate Array Args";
public static final String ENABLE_EXIT_STACK_TRACE = "Add Stacktrace to Exit";
public static final String BEGIN_CAPTURE_CALLERS = "New Callers Capture...";
public static final String END_CAPTURE_CALLERS = "End Callers Capture";

View File

@ -787,6 +787,7 @@ public class InTraceUI implements ISocketCallback, IControlConnectionListener
final Button branchTrace;
final Button argsTrace;
final Button arrayTrace;
final Button exitStackTrace;
final Composite composite;
@ -813,6 +814,11 @@ public class InTraceUI implements ISocketCallback, IControlConnectionListener
arrayTrace.setText(ClientStrings.ENABLE_ARRAY_TRACE);
arrayTrace.setAlignment(SWT.CENTER);
exitStackTrace = new Button(composite, SWT.CHECK);
exitStackTrace.setText(ClientStrings.ENABLE_EXIT_STACK_TRACE);
exitStackTrace.setAlignment(SWT.CENTER);
entryExitTrace
.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter()
{
@ -857,6 +863,17 @@ public class InTraceUI implements ISocketCallback, IControlConnectionListener
settingsData.truncArraysEnabled = !settingsData.truncArraysEnabled;
}
});
exitStackTrace
.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent arg0)
{
toggleSetting(settingsData.exitStackTrace, "[exit-stack-trace-true",
"[exit-stack-trace-false");
settingsData.exitStackTrace = !settingsData.exitStackTrace;
}
});
}
}
@ -2209,6 +2226,7 @@ public class InTraceUI implements ISocketCallback, IControlConnectionListener
settingsTabs.traceTab.argsTrace.setEnabled(true);
settingsTabs.traceTab.branchTrace.setEnabled(true);
settingsTabs.traceTab.exitStackTrace.setEnabled(true);
settingsTabs.traceTab.entryExitTrace.setEnabled(true);
settingsTabs.traceTab.arrayTrace.setEnabled(true);
settingsTabs.agentOutputSettingsTab.fileOutput.setEnabled(true);
@ -2223,6 +2241,7 @@ public class InTraceUI implements ISocketCallback, IControlConnectionListener
// Update the button pressed/unpressed state
settingsTabs.traceTab.argsTrace.setSelection(settingsData.argsEnabled);
settingsTabs.traceTab.branchTrace.setSelection(settingsData.branchEnabled);
settingsTabs.traceTab.exitStackTrace.setSelection(settingsData.exitStackTrace);
settingsTabs.traceTab.entryExitTrace.setSelection(settingsData.entryExitEnabled);
settingsTabs.traceTab.arrayTrace.setSelection(settingsData.truncArraysEnabled);
settingsTabs.agentOutputSettingsTab.fileOutput.setSelection(settingsData.fileOutEnabled);
@ -2261,6 +2280,7 @@ public class InTraceUI implements ISocketCallback, IControlConnectionListener
settingsTabs.traceTab.argsTrace.setEnabled(false);
settingsTabs.traceTab.branchTrace.setEnabled(false);
settingsTabs.traceTab.exitStackTrace.setEnabled(false);
settingsTabs.traceTab.entryExitTrace.setEnabled(false);
settingsTabs.traceTab.arrayTrace.setEnabled(false);
settingsTabs.agentOutputSettingsTab.fileOutput.setEnabled(false);

View File

@ -19,6 +19,8 @@ public class ParsedSettingsData
public boolean gzipEnabled = false;
public boolean truncArraysEnabled;
public boolean argsEnabled;
public boolean exitStackTrace = false;
public boolean stdOutEnabled;
public boolean fileOutEnabled;
public boolean netOutEnabled;
@ -45,6 +47,15 @@ public class ParsedSettingsData
gzipEnabled = false;
}
if ("true".equals(settingsMap.get(AgentConfigConstants.EXIT_STACK_TRACE)))
{
exitStackTrace = true;
}
else
{
exitStackTrace = false;
}
classRegex = settingsMap.get(AgentConfigConstants.CLASS_REGEX);
classExcludeRegex = settingsMap
.get(AgentConfigConstants.EXCLUDE_CLASS_REGEX);

View File

@ -4,8 +4,10 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.intrace.output.AgentHelper;
@ -16,6 +18,12 @@ import org.intrace.output.IInstrumentationHandler;
*/
public class TraceHandler implements IInstrumentationHandler
{
/**
* Including the period at the end enables code in "org.intracetest" to be included in the trace
*/
private static final String INTRACE_PACKAGE = "org.intrace.";
private static final String THREAD = "java.lang.Thread";
private static final String GET_STACK_TRACE = "getStackTrace";
public static final TraceHandler INSTANCE = new TraceHandler();
private TraceHandler()
{
@ -26,7 +34,8 @@ public class TraceHandler implements IInstrumentationHandler
private boolean branchTrace = false;
private boolean argTrace = true;
private boolean truncateArrays = true;
private boolean exitStackTrace = false;
private static final TraceSettings traceSettings = new TraceSettings("");
public String getResponse(String args)
@ -50,7 +59,8 @@ public class TraceHandler implements IInstrumentationHandler
branchTrace = traceSettings.isBranchTraceEnabled();
argTrace = traceSettings.isArgTraceEnabled();
truncateArrays = traceSettings.isTruncateArraysEnabled();
exitStackTrace = traceSettings.isExitStackTraceEnabled();
return null;
}
@ -251,6 +261,15 @@ public class TraceHandler implements IInstrumentationHandler
}
private static final char ESCAPE_REPLACEMENT = '\u25A1';
/**
* If user has requested to see a stack trace for each 'exit' event (with the parameter [exit-stack-trace-true) , then
* this delimiter will follow the regular event text, which will be followed by the text of the stack trace.
*/
private static final String STACK_TRACE_DELIM = "~";
/**
* Just like Arrays.toString(Object), place a comma between each element of the stack trace
*/
private static final Object STACK_ELE_DELIM = ",";
private String replaceChars(String xiArg)
{
@ -384,13 +403,38 @@ public class TraceHandler implements IInstrumentationHandler
}
}
/**
* Remove all "org.intrace" elements from the current stack trace and return it as string.
* @return
*/
public String getStackTrace() {
StringBuilder sb = new StringBuilder();
int counter = 0;
for(StackTraceElement ste : Thread.currentThread().getStackTrace() ) {
if ( ste.getClassName().indexOf(INTRACE_PACKAGE) <0
&& (ste.getClassName().indexOf(THREAD) < 0) && ste.getMethodName().indexOf(GET_STACK_TRACE)<0) {
if (counter++>0) sb.append(STACK_ELE_DELIM); //Just like Arrays.toString(), place a comma between each stack trace ele.
sb.append(ste.toString());
}
}
return sb.toString();
}
@Override
public void exit(String className, String methodName, int lineNo)
{
if (entryExitTrace)
{
writeTraceOutput(className + ":" + methodName + ": }" +
(lineNo >= 0 ? ":" + lineNo : ""));
if (exitStackTrace) {
writeTraceOutput(className + ":" + methodName + ": }" +
(lineNo >= 0 ? ":" + lineNo : "") +
STACK_TRACE_DELIM + getStackTrace() );
} else {
writeTraceOutput(className + ":" + methodName + ": }" +
(lineNo >= 0 ? ":" + lineNo : "") );
}
}
}

View File

@ -17,6 +17,16 @@ public class TraceSettings
private boolean branchTraceEnabled = false;
private boolean argTraceEnabled = true;
private boolean truncateArraysEnabled = true;
/**
* If true, append the 'current' stack trace to the text of the exit trace event.
* This is helpful for discovering who is invoking a particular line of code.
* Here is an example of the trace output:
* <PRE>
* [07:53:15.509]:[1]:example.FirstTraceExample:intArrayMethod: }:70~java.lang.Thread.getStackTrace(Thread.java:1567),example.FirstTraceExample.intArrayMethod(FirstTraceExample.java:70),example.FirstTraceExample.workMethod(FirstTraceExample.java:38),example.FirstTraceExample.otherMain(FirstTraceExample.java:29),example.FirstTraceExample.main(FirstTraceExample.java:16)
* </PRE>
*/
private boolean exitStackTrace = false;
public TraceSettings(TraceSettings oldSettings)
{
@ -24,6 +34,7 @@ public class TraceSettings
branchTraceEnabled = oldSettings.branchTraceEnabled;
argTraceEnabled = oldSettings.argTraceEnabled;
truncateArraysEnabled = oldSettings.truncateArraysEnabled;
exitStackTrace = oldSettings.exitStackTrace;
}
public TraceSettings(String args)
@ -74,6 +85,14 @@ public class TraceSettings
{
truncateArraysEnabled = false;
}
else if (arg.equals(TraceConfigConstants.EXIT_STACK_TRACE + "false"))
{
exitStackTrace = false;
}
else if (arg.equals(TraceConfigConstants.EXIT_STACK_TRACE + "true"))
{
exitStackTrace = true;
}
}
public boolean isEntryExitTraceEnabled()
@ -95,6 +114,9 @@ public class TraceSettings
{
return truncateArraysEnabled;
}
public boolean isExitStackTraceEnabled() {
return exitStackTrace;
}
public Map<String, String> getSettingsMap()
{
@ -107,6 +129,9 @@ public class TraceSettings
.put(TraceConfigConstants.ARG, Boolean.toString(argTraceEnabled));
settingsMap
.put(TraceConfigConstants.ARRAYS, Boolean.toString(truncateArraysEnabled));
settingsMap.put(TraceConfigConstants.EXIT_STACK_TRACE,
Boolean.toString(exitStackTrace));
return settingsMap;
}
}

View File

@ -24,6 +24,7 @@ public class AgentConfigConstants
public static final String VERBOSE_MODE = "[verbose-";
public static final String OPT_SERVER_PORT = "[serverport-";
public static final String CALLBACK_PORT = "[callbackport-";
public static final String EXIT_STACK_TRACE = "[exit-stack-trace-";
public static final String START_WAIT = "[startwait";
public static final String START_ACTIVATE = "[startactivate";
@ -39,5 +40,6 @@ public class AgentConfigConstants
COMMANDS.add(OPT_SERVER_PORT + "<int>");
COMMANDS.add(CALLBACK_PORT + "<int>");
COMMANDS.add(GZIP + "<true/false>");
COMMANDS.add(EXIT_STACK_TRACE + "<true/false>");
}
}

View File

@ -12,6 +12,7 @@ public class TraceConfigConstants
public static final String STD_OUT = "[out-stdout-";
public static final String FILE_OUT = "[out-file-";
public static final String NET_OUT = "[out-network-";
public static final String EXIT_STACK_TRACE = "[exit-stack-trace-";
public static final Set<String> COMMANDS = new HashSet<String>();
static
{
@ -22,5 +23,6 @@ public class TraceConfigConstants
COMMANDS.add(STD_OUT + "<true/false>");
COMMANDS.add(FILE_OUT + "<true/false>");
COMMANDS.add(NET_OUT + "<true/false>");
COMMANDS.add(EXIT_STACK_TRACE + "<true/false>");
}
}

View File

@ -0,0 +1,63 @@
package org.intracetest.agent;
import java.util.Map;
import junit.framework.TestCase;
import org.intrace.agent.AgentSettings;
import org.intrace.output.trace.TraceHandler;
import org.intrace.output.trace.TraceSettings;
import org.intrace.shared.AgentConfigConstants;
import org.intrace.shared.TraceConfigConstants;
public class StackTraceTest extends TestCase
{
private static final String MY_PACKAGE_AND_CLASS = "org.intracetest.agent.StackTraceTest";
private String m_stackTrace;
/** Here is the raw stack trace that we want to validate:
* <PRE>
org.intracetest.agent.StackTraceTest.c(StackTraceTest.java:57),org.intracetest.agent.StackTraceTest.b(StackTraceTest.java:54),org.intracetest.agent.StackTraceTest.a(StackTraceTest.java:51),org.intracetest.agent.StackTraceTest.testStackTrace(StackTraceTest.java:27),sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method),sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57),sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43),java.lang.reflect.Method.invoke(Method.java:601),junit.framework.TestCase.runTest(TestCase.java:168),junit.framework.TestCase.runBare(TestCase.java:134),junit.framework.TestResult$1.protect(TestResult.java:110),junit.framework.TestResult.runProtected(TestResult.java:128),junit.framework.TestResult.run(TestResult.java:113),junit.framework.TestCase.run(TestCase.java:124),junit.framework.TestSuite.runTest(TestSuite.java:243),junit.framework.TestSuite.run(TestSuite.java:238),org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83),org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50),org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38),org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467),org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683),org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390),org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
* </PRE>
* Among other things, this test validates that the following are removed from the stack trace:
* <ul>
* <li>java.lang.Thread.getStackTrace</li>
* <li>all org.intrace. activity</li>
* </ul>
*
*/
public void testStackTrace()
{
a();
String[] parts = m_stackTrace.split(",");
//System.out.println(m_stackTrace);
//JUnit has a thick call stack -- when I checked, there were 23 stack trace elements.
//Application developers only care about the ones on the very top.
assertTrue("Didn't not find the right number of StackTraceElements", parts.length > 4);
validateStackTraceElement("org.intracetest.agent.StackTraceTest.c", parts[0]);
validateStackTraceElement("org.intracetest.agent.StackTraceTest.b", parts[1]);
validateStackTraceElement("org.intracetest.agent.StackTraceTest.a", parts[2]);
validateStackTraceElement("org.intracetest.agent.StackTraceTest.testStackTrace", parts[3]);
//validateStackTraceElement("sun.reflect.NativeMethodAccessorImpl.invoke0", parts[4]);
}
private void validateStackTraceElement(String expectedPackageAndClassAndMethod, String actual) {
String[] partsOfStackTraceElement = actual.split("[\\(:\\)]");
assertEquals("The package and class and method name were not found in the right place",
expectedPackageAndClassAndMethod,
partsOfStackTraceElement[0]);
assertEquals("source file not found in the right place",
"StackTraceTest.java",
partsOfStackTraceElement[1]);
}
private void a() {
b();
}
private void b() {
c();
}
private void c() {
m_stackTrace = TraceHandler.INSTANCE.getStackTrace();
}
}

View File

@ -22,17 +22,21 @@ public class TraceSettingsTest extends TestCase
+ "true"
+ TraceConfigConstants.BRANCH
+ "true"
+ TraceConfigConstants.EXIT_STACK_TRACE
+ "true"
);
assertTrue(ts.isArgTraceEnabled());
assertTrue(ts.isEntryExitTraceEnabled());
assertTrue(ts.isBranchTraceEnabled());
assertTrue(ts.isExitStackTraceEnabled());
assertTrue(ts.isTruncateArraysEnabled());
ts = new TraceSettings(ts);
assertTrue(ts.isArgTraceEnabled());
assertTrue(ts.isEntryExitTraceEnabled());
assertTrue(ts.isBranchTraceEnabled());
assertTrue(ts.isExitStackTraceEnabled());
assertTrue(ts.isTruncateArraysEnabled());
String toString = ts.toString();
@ -42,6 +46,7 @@ public class TraceSettingsTest extends TestCase
assertEquals(settingsMap.get(TraceConfigConstants.ARG), "true");
assertEquals(settingsMap.get(TraceConfigConstants.ARRAYS), "true");
assertEquals(settingsMap.get(TraceConfigConstants.BRANCH), "true");
assertEquals(settingsMap.get(TraceConfigConstants.EXIT_STACK_TRACE),"true");
assertEquals(settingsMap.get(TraceConfigConstants.ENTRY_EXIT), "true");
}