mirror of https://github.com/mchr3k/org.intrace
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:
parent
e756ba0d84
commit
560fa99eed
Binary file not shown.
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 : "") );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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>");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue