mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-147000 Support YourKit thread dump format in Analyze stacktrace
This commit is contained in:
@@ -21,7 +21,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -31,6 +30,7 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public class ThreadDumpParser {
|
||||
private static final Pattern ourThreadStartPattern = Pattern.compile("^\\s*\"(.+)\".+(prio=\\d+ (?:os_prio=[^\\s]+ )?tid=[^\\s]+ nid=[^\\s]+|[Ii][Dd]=\\d+) ([^\\[]+)");
|
||||
private static final Pattern ourYourkitThreadStartPattern = Pattern.compile("(.+) \\[([^\\[]*)]");
|
||||
private static final Pattern ourThreadStatePattern = Pattern.compile("java\\.lang\\.Thread\\.State: (.+) \\((.+)\\)");
|
||||
private static final Pattern ourThreadStatePattern2 = Pattern.compile("java\\.lang\\.Thread\\.State: (.+)");
|
||||
private static final Pattern ourWaitingForLockPattern = Pattern.compile("- waiting (on|to lock) <(.+)>");
|
||||
@@ -197,6 +197,16 @@ public class ThreadDumpParser {
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
String noDaemon = StringUtil.trimEnd(line, " [DAEMON]");
|
||||
m = ourYourkitThreadStartPattern.matcher(noDaemon);
|
||||
if (m.find()) {
|
||||
ThreadState state = new ThreadState(m.group(1), m.group(2));
|
||||
if (noDaemon.length() < line.length()) {
|
||||
state.setDaemon(true);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,18 +62,28 @@ public class ExceptionWorkerTest extends LightCodeInsightFixtureTestCase {
|
||||
|
||||
public void testAnomalyParenthesisParsing() {
|
||||
String[][] data = new String[][]{
|
||||
{"at youtrack.jetbrains.com.Issue.IDEA_125137()(FooTest.groovy:2)", "youtrack.jetbrains.com.Issue", "IDEA_125137()",
|
||||
{"at youtrack.jetbrains.com.Issue.IDEA_125137()(FooTest.groovy:2)\n", "youtrack.jetbrains.com.Issue", "IDEA_125137()",
|
||||
"FooTest.groovy:2"},
|
||||
{"at youtrack.jetbrains.com.Issue.IDEA_125137()Hmm(FooTest.groovy:2)", "youtrack.jetbrains.com.Issue", "IDEA_125137()Hmm",
|
||||
{"at youtrack.jetbrains.com.Issue.IDEA_125137()Hmm(FooTest.groovy:2)\n", "youtrack.jetbrains.com.Issue", "IDEA_125137()Hmm",
|
||||
"FooTest.groovy:2"},
|
||||
{"p1.Cl.mee(p1.Cl.java:87) (A MESSAGE) IDEA-133794 (BUG START WITH 1)", "p1.Cl", "mee", "p1.Cl.java:87"}
|
||||
{"p1.Cl.mee(p1.Cl.java:87) (A MESSAGE) IDEA-133794 (BUG START WITH 1)\n", "p1.Cl", "mee", "p1.Cl.java:87"}
|
||||
};
|
||||
for (String[] datum : data) {
|
||||
Trinity<TextRange, TextRange, TextRange> trinity = ExceptionWorker.parseExceptionLine(datum[0]);
|
||||
assertNotNull(trinity);
|
||||
assertEquals(datum[1], trinity.first.subSequence(datum[0]));
|
||||
assertEquals(datum[2], trinity.second.subSequence(datum[0]));
|
||||
assertEquals(datum[3], trinity.third.subSequence(datum[0]));
|
||||
assertParsed(datum[0], datum[1], datum[2], datum[3]);
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertParsed(String line, String className, String methodName, String fileLine) {
|
||||
assertTrue(line.endsWith("\n"));
|
||||
Trinity<TextRange, TextRange, TextRange> trinity = ExceptionWorker.parseExceptionLine(line);
|
||||
assertNotNull(trinity);
|
||||
assertEquals(className, trinity.first.subSequence(line));
|
||||
assertEquals(methodName, trinity.second.subSequence(line));
|
||||
assertEquals(fileLine, trinity.third.subSequence(line));
|
||||
}
|
||||
|
||||
public void testYourKitFormat() {
|
||||
assertParsed("com.intellij.util.concurrency.Semaphore.waitFor(long) Semaphore.java:89\n",
|
||||
"com.intellij.util.concurrency.Semaphore", "waitFor", "Semaphore.java:89");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,5 +96,28 @@ class ThreadDumpParserTest extends TestCase {
|
||||
assert threads[0].isAwaitedBy(threads[1])
|
||||
}
|
||||
|
||||
void "test YourKit format"() {
|
||||
def text = """
|
||||
Stacks at 2017-05-03 01:07:25 PM (uptime 4h 21m 28s) Threads shown: 38 of 46
|
||||
|
||||
ApplicationImpl pooled thread 228 [WAITING]
|
||||
java.lang.Thread.run() Thread.java:745
|
||||
|
||||
ApplicationImpl pooled thread 234 [WAITING] [DAEMON]
|
||||
java.lang.Thread.run() Thread.java:745
|
||||
|
||||
ApplicationImpl pooled thread 6 [RUNNABLE, IN_NATIVE]
|
||||
java.net.DatagramSocket.receive(DatagramPacket) DatagramSocket.java:812
|
||||
com.intellij.a.f.a.c.a() c.java:60
|
||||
com.intellij.a.f.a.d.run() d.java:20
|
||||
java.lang.Thread.run() Thread.java:745
|
||||
"""
|
||||
def threads = ThreadDumpParser.parse(text)
|
||||
assert threads.collect { it.name } == ['ApplicationImpl pooled thread 228', 'ApplicationImpl pooled thread 234', 'ApplicationImpl pooled thread 6']
|
||||
assert threads.collect { it.state } == ['WAITING', 'WAITING', 'RUNNABLE, IN_NATIVE']
|
||||
assert threads.collect { it.daemon } == [false, true, false]
|
||||
assert threads.collect { it.stackTrace.readLines().size() } == [2, 2, 5] // thread name is included into stack trace
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -167,24 +167,14 @@ public class ExceptionWorker {
|
||||
return myInfo;
|
||||
}
|
||||
|
||||
//todo [roma] regexp
|
||||
@Nullable
|
||||
static Trinity<TextRange, TextRange, TextRange> parseExceptionLine(final String line) {
|
||||
int startIdx;
|
||||
if (line.startsWith(AT_PREFIX)){
|
||||
startIdx = 0;
|
||||
}
|
||||
else{
|
||||
startIdx = line.indexOf(STANDALONE_AT);
|
||||
if (startIdx < 0) {
|
||||
startIdx = line.indexOf(AT_PREFIX);
|
||||
}
|
||||
private static int findAtPrefix(String line) {
|
||||
if (line.startsWith(AT_PREFIX)) return 0;
|
||||
|
||||
if (startIdx < 0) {
|
||||
startIdx = -1;
|
||||
}
|
||||
}
|
||||
int startIdx = line.indexOf(STANDALONE_AT);
|
||||
return startIdx < 0 ? line.indexOf(AT_PREFIX) : startIdx;
|
||||
}
|
||||
|
||||
private static int findFirstRParenAfterDigit(String line) {
|
||||
int rParenIdx = -1;
|
||||
int rParenCandidate = line.lastIndexOf(')');
|
||||
//Looking for minimal position for ')' after a digit
|
||||
@@ -194,6 +184,15 @@ public class ExceptionWorker {
|
||||
}
|
||||
rParenCandidate = line.lastIndexOf(')', rParenCandidate - 1);
|
||||
}
|
||||
return rParenIdx;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Trinity<TextRange, TextRange, TextRange> parseExceptionLine(final String line) {
|
||||
int startIdx = findAtPrefix(line);
|
||||
|
||||
TextRange yourKitLink = startIdx < 0 ? getYourKitLinkRange(line) : null;
|
||||
int rParenIdx = yourKitLink != null ? yourKitLink.getEndOffset() - 2 : findFirstRParenAfterDigit(line);
|
||||
if (rParenIdx < 0) return null;
|
||||
|
||||
final int lParenIdx = line.lastIndexOf('(', rParenIdx);
|
||||
@@ -207,7 +206,21 @@ public class ExceptionWorker {
|
||||
// class, method, link
|
||||
return Trinity.create(new TextRange(classNameIdx, handleSpaces(line, dotIdx, -1)),
|
||||
new TextRange(handleSpaces(line, dotIdx + 1, 1), handleSpaces(line, lParenIdx, -1)),
|
||||
new TextRange(lParenIdx + 1, rParenIdx));
|
||||
yourKitLink != null ? yourKitLink : new TextRange(lParenIdx + 1, rParenIdx));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TextRange getYourKitLinkRange(String line) {
|
||||
int lineEnd = line.length() - 1;
|
||||
if (lineEnd > 0 && line.charAt(lineEnd) == '\n') lineEnd--;
|
||||
if (lineEnd > 0 && Character.isDigit(line.charAt(lineEnd))) {
|
||||
int spaceIndex = line.lastIndexOf(' ');
|
||||
int rParenIdx = line.lastIndexOf(')');
|
||||
if (rParenIdx > 0 && spaceIndex == rParenIdx + 1) {
|
||||
return new TextRange(spaceIndex + 1, lineEnd + 1);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int handleSpaces(String line, int pos, int delta) {
|
||||
|
||||
Reference in New Issue
Block a user