Author: thomasm
Date: Fri Jul 1 12:15:54 2016
New Revision: 1750920
URL: http://svn.apache.org/viewvc?rev=1750920&view=rev
Log:
OAK-4521 Oak-run: add profiling and analysis tools
Added:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/ThreadDumpCommand.java
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/threadDump/
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/threadDump/ThreadDumpCleaner.java
Modified:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/util/Profiler.java
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Mode.java
Modified:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/util/Profiler.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/util/Profiler.java?rev=1750920&r1=1750919&r2=1750920&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/util/Profiler.java
(original)
+++
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/util/Profiler.java
Fri Jul 1 12:15:54 2016
@@ -17,13 +17,16 @@
package org.apache.jackrabbit.oak.benchmark.util;
import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStream;
+import java.io.Reader;
import java.io.StringReader;
-import java.util.ArrayList;
import java.lang.instrument.Instrumentation;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -32,26 +35,38 @@ import java.util.Map;
/**
* A simple CPU profiling tool similar to java -Xrunhprof. It can be used
* in-process (to profile the current application) or as a standalone program
- * (to profile a different process).
+ * (to profile a different process, or files containing full thread dumps).
*/
public class Profiler implements Runnable {
private static Instrumentation instrumentation;
- private static final String LINE_SEPARATOR =
System.getProperty("line.separator", "\n");
+ private static final String LINE_SEPARATOR =
+ System.getProperty("line.separator", "\n");
private static final int MAX_ELEMENTS = 1000;
public int interval = 2;
public int depth = 48;
public boolean paused;
public boolean sumClasses;
+ public boolean sumMethods;
private int pid;
- private final String[] ignoreLines = {};
+ private final String[] ignoreLines = (
+ "java," +
+ "sun," +
+ "com.sun.," +
+ "com.google.common.," +
+ "com.mongodb.," +
+ "org.bson.,"
+ ).split(",");
private final String[] ignorePackages = (
"java," +
"sun," +
- "com.sun."
+ "com.sun.," +
+ "com.google.common.," +
+ "com.mongodb.," +
+ "org.bson"
).split(",");
private final String[] ignoreThreads = (
"java.lang.Object.wait," +
@@ -59,29 +74,37 @@ public class Profiler implements Runnabl
"java.lang.Thread.getThreads," +
"java.lang.Thread.sleep," +
"java.lang.UNIXProcess.waitForProcessExit," +
+ "java.net.PlainDatagramSocketImpl.receive0," +
"java.net.PlainSocketImpl.accept," +
"java.net.PlainSocketImpl.socketAccept," +
"java.net.SocketInputStream.socketRead," +
"java.net.SocketOutputStream.socketWrite," +
+ "org.eclipse.jetty.io.nio.SelectorManager$SelectSet.doSelect," +
"sun.awt.windows.WToolkit.eventLoop," +
"sun.misc.Unsafe.park," +
+ "sun.nio.ch.EPollArrayWrapper.epollWait," +
+ "sun.nio.ch.KQueueArrayWrapper.kevent0," +
+ "sun.nio.ch.ServerSocketChannelImpl.accept," +
"dalvik.system.VMStack.getThreadStackTrace," +
"dalvik.system.NativeStart.run"
).split(",");
private volatile boolean stop;
- private final HashMap<String, Integer> counts = new HashMap<String,
Integer>();
+ private final HashMap<String, Integer> counts =
+ new HashMap<String, Integer>();
/**
* The summary (usually one entry per package, unless sumClasses is
enabled,
* in which case it's one entry per class).
*/
- private final HashMap<String, Integer> summary = new HashMap<String,
Integer>();
+ private final HashMap<String, Integer> summary =
+ new HashMap<String, Integer>();
private int minCount = 1;
private int total;
private Thread thread;
private long start;
private long time;
+ private int threadDumps;
/**
* This method is called when the agent is installed.
@@ -116,24 +139,67 @@ public class Profiler implements Runnabl
private void run(String... args) {
if (args.length == 0) {
System.out.println("Show profiling data");
- System.out.println("Usage: java " + getClass().getName() + "
<pid>");
+ System.out.println("Usage: java " + getClass().getName() +
+ " <pid> | <stackTraceFileNames>");
System.out.println("Processes:");
String processes = exec("jps", "-l");
System.out.println(processes);
return;
}
- pid = Integer.parseInt(args[0]);
start = System.currentTimeMillis();
- long last = 0;
- while (true) {
- tick();
- long t = System.currentTimeMillis();
- if (t - last > 5000) {
- time = System.currentTimeMillis() - start;
- System.out.println(getTopTraces(3));
- last = t;
+ if (args[0].matches("\\d+")) {
+ pid = Integer.parseInt(args[0]);
+ long last = 0;
+ while (true) {
+ tick();
+ long t = System.currentTimeMillis();
+ if (t - last > 5000) {
+ time = System.currentTimeMillis() - start;
+ System.out.println(getTopTraces(3));
+ last = t;
+ }
}
}
+ try {
+ for (String arg : args) {
+ if (arg.startsWith("-")) {
+ if ("-classes".equals(arg)) {
+ sumClasses = true;
+ } else if ("-methods".equals(arg)) {
+ sumMethods = true;
+ } else if ("-packages".equals(arg)) {
+ sumClasses = false;
+ sumMethods = false;
+ } else {
+ throw new IllegalArgumentException(arg);
+ }
+ continue;
+ }
+ String file = arg;
+ Reader reader;
+ LineNumberReader r;
+ reader = new InputStreamReader(
+ new FileInputStream(file), "CP1252");
+ r = new LineNumberReader(reader);
+ while (true) {
+ String line = r.readLine();
+ if (line == null) {
+ break;
+ } else if (line.startsWith("Full thread dump")) {
+ threadDumps++;
+ }
+ }
+ reader.close();
+ reader = new InputStreamReader(
+ new FileInputStream(file), "CP1252");
+ r = new LineNumberReader(reader);
+ processList(readStackTrace(r));
+ reader.close();
+ }
+ System.out.println(getTopTraces(5));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
private static List<Object[]> getRunnableStackTraces() {
@@ -154,52 +220,58 @@ public class Profiler implements Runnabl
}
private static List<Object[]> readRunnableStackTraces(int pid) {
- ArrayList<Object[]> list = new ArrayList<Object[]>();
try {
String jstack = exec("jstack", "" + pid);
- LineNumberReader r = new LineNumberReader(new
StringReader(jstack));
+ LineNumberReader r = new LineNumberReader(
+ new StringReader(jstack));
+ return readStackTrace(r);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static List<Object[]> readStackTrace(LineNumberReader r)
+ throws IOException {
+ ArrayList<Object[]> list = new ArrayList<Object[]>();
+ while (true) {
+ String line = r.readLine();
+ if (line == null) {
+ break;
+ }
+ if (!line.startsWith("\"")) {
+ // not a thread
+ continue;
+ }
+ line = r.readLine();
+ if (line == null) {
+ break;
+ }
+ line = line.trim();
+ if (!line.startsWith("java.lang.Thread.State: RUNNABLE")) {
+ continue;
+ }
+ ArrayList<String> stack = new ArrayList<String>();
while (true) {
- String line = r.readLine();
- if (line == null) {
- break;
- }
- if (!line.startsWith("\"")) {
- // not a thread
- continue;
- }
line = r.readLine();
if (line == null) {
break;
}
line = line.trim();
- if (!line.startsWith("java.lang.Thread.State: RUNNABLE")) {
+ if (line.startsWith("- ")) {
continue;
}
- ArrayList<String> stack = new ArrayList<String>();
- while (true) {
- line = r.readLine();
- if (line == null) {
- break;
- }
- line = line.trim();
- if (line.startsWith("- ")) {
- continue;
- }
- if (!line.startsWith("at ")) {
- break;
- }
- line = line.substring(3).trim();
- stack.add(line);
- }
- if (stack.size() > 0) {
- String[] s = stack.toArray(new String[stack.size()]);
- list.add(s);
+ if (!line.startsWith("at ")) {
+ break;
}
+ line = line.substring(3).trim();
+ stack.add(line);
+ }
+ if (stack.size() > 0) {
+ String[] s = stack.toArray(new String[stack.size()]);
+ list.add(s);
}
- return list;
- } catch (IOException e) {
- throw new RuntimeException(e);
}
+ return list;
}
private static String exec(String... args) {
@@ -221,7 +293,8 @@ public class Profiler implements Runnabl
}
}
- private static void copyInThread(final InputStream in, final OutputStream
out) {
+ private static void copyInThread(final InputStream in,
+ final OutputStream out) {
new Thread("Profiler stream copy") {
@Override
public void run() {
@@ -238,7 +311,7 @@ public class Profiler implements Runnabl
throw new RuntimeException(e);
}
}
- }.run();
+ }.start();
}
/**
@@ -302,6 +375,11 @@ public class Profiler implements Runnabl
} else {
list = getRunnableStackTraces();
}
+ threadDumps++;
+ processList(list);
+ }
+
+ private void processList(List<Object[]> list) {
for (Object[] dump : list) {
if (startsWithAny(dump[0].toString(), ignoreThreads)) {
continue;
@@ -331,6 +409,10 @@ public class Profiler implements Runnabl
int m = el.indexOf('.', index + 1);
index = m >= 0 ? m : index;
}
+ if (sumMethods) {
+ int m = el.indexOf('(', index + 1);
+ index = m >= 0 ? m : index;
+ }
String groupName = el.substring(0, index);
increment(summary, groupName, 0);
}
@@ -353,7 +435,8 @@ public class Profiler implements Runnabl
return false;
}
- private static int increment(HashMap<String, Integer> map, String trace,
int minCount) {
+ private static int increment(HashMap<String, Integer> map, String trace,
+ int minCount) {
Integer oldCount = map.get(trace);
if (oldCount == null) {
map.put(trace, 1);
@@ -361,7 +444,8 @@ public class Profiler implements Runnabl
map.put(trace, oldCount + 1);
}
while (map.size() > MAX_ELEMENTS) {
- for (Iterator<Map.Entry<String, Integer>> ei =
map.entrySet().iterator(); ei.hasNext();) {
+ for (Iterator<Map.Entry<String, Integer>> ei =
+ map.entrySet().iterator(); ei.hasNext();) {
Map.Entry<String, Integer> e = ei.next();
if (e.getValue() <= minCount) {
ei.remove();
@@ -387,8 +471,14 @@ public class Profiler implements Runnabl
private String getTopTraces(int count) {
StringBuilder buff = new StringBuilder();
- buff.append("Profiler: top ").append(count).append(" stack trace(s) of
").append(time).
- append(" ms:").append(LINE_SEPARATOR);
+ buff.append("Profiler: top ").append(count).append(" stack trace(s) of
");
+ if (time > 0) {
+ buff.append(" of ").append(time).append(" ms");
+ }
+ if (threadDumps > 0) {
+ buff.append(" of ").append(threadDumps).append(" thread dumps");
+ }
+ buff.append(":").append(LINE_SEPARATOR);
if (counts.size() == 0) {
buff.append("(none)").append(LINE_SEPARATOR);
}
@@ -401,7 +491,8 @@ public class Profiler implements Runnabl
return buff.toString();
}
- private static void appendTop(StringBuilder buff, HashMap<String, Integer>
map, int count, int total, boolean table) {
+ private static void appendTop(StringBuilder buff,
+ HashMap<String, Integer> map, int count, int total, boolean table)
{
for (int x = 0, min = 0;;) {
int highest = 0;
Map.Entry<String, Integer> best = null;
Modified:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Mode.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Mode.java?rev=1750920&r1=1750919&r2=1750920&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Mode.java
(original)
+++
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Mode.java
Fri Jul 1 12:15:54 2016
@@ -44,6 +44,7 @@ enum Mode {
DUMPDATASTOREREFS("dumpdatastorerefs", new DataStoreCheckCommand()),
RESETCLUSTERID("resetclusterid", new ResetClusterIdCommand()),
PERSISTENTCACHE("persistentcache", new PersistentCacheCommand()),
+ THREADDUMP("threaddump", new ThreadDumpCommand()),
HELP("help", new HelpCommand());
private final String name;
Added:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/ThreadDumpCommand.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/ThreadDumpCommand.java?rev=1750920&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/ThreadDumpCommand.java
(added)
+++
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/ThreadDumpCommand.java
Fri Jul 1 12:15:54 2016
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.run;
+
+import static java.util.Arrays.asList;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.GZIPInputStream;
+
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+import joptsimple.OptionSpec;
+
+import org.apache.jackrabbit.oak.benchmark.util.Profiler;
+import org.apache.jackrabbit.oak.threadDump.ThreadDumpCleaner;
+
+public class ThreadDumpCommand implements Command {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void execute(String... args) throws Exception {
+ OptionParser parser = new OptionParser();
+ OptionSpec<Void> filterSpec = parser.accepts("filter",
+ "filter the thread dumps, only keep working threads");
+ OptionSpec<Void> profileSpec = parser.accepts("profile",
+ "profile the thread dumps");
+ OptionSpec<Void> profileClassesSpec = parser.accepts("profileClasses",
+ "profile classes");
+ OptionSpec<Void> profileMethodsSpec = parser.accepts("profileMethods",
+ "profile methods");
+ OptionSpec<Void> profilePackagesSpec =
parser.accepts("profilePackages",
+ "profile packages");
+ OptionSpec<?> helpSpec = parser.acceptsAll(
+ asList("h", "?", "help"), "show help").forHelp();
+ OptionSet options = parser.parse(args);
+ parser.nonOptions(
+ "file or directory containing thread
dumps").ofType(File.class);
+ if (options.has(helpSpec)
+ || options.nonOptionArguments().isEmpty()) {
+ System.out.println("Mode: " + Mode.THREADDUMP);
+ System.out.println();
+ parser.printHelpOn(System.out);
+ return;
+ }
+ boolean filter = options.has(filterSpec);
+ boolean profile = options.has(profileSpec);
+ boolean profileClasses = options.has(profileClassesSpec);
+ boolean profileMethods = options.has(profileMethodsSpec);
+ boolean profilePackages = options.has(profilePackagesSpec);
+ for (String fileName : ((List<String>) options.nonOptionArguments())) {
+ File file = new File(fileName);
+ if (file.isDirectory() || file.getName().endsWith(".gz")) {
+ file = combineAndExpandFiles(file);
+ System.out.println("Combined into " + file.getAbsolutePath());
+ }
+ if (filter) {
+ file = ThreadDumpCleaner.process(file);
+ System.out.println("Filtered into " + file.getAbsolutePath());
+ }
+ if (profile) {
+ ArrayList<String> list = new ArrayList<String>();
+ if (profileClasses) {
+ list.add("-classes");
+ }
+ if (profileMethods) {
+ list.add("-methods");
+ }
+ if (profilePackages) {
+ list.add("-packages");
+ }
+ list.add(file.getAbsolutePath());
+ Profiler.main(list.toArray(new String[0]));
+ }
+ }
+ }
+
+ private static File combineAndExpandFiles(File file) throws IOException {
+ if (!file.exists() || !file.isDirectory()) {
+ if (!file.getName().endsWith(".gz")) {
+ return file;
+ }
+ }
+ File target = new File(file.getParentFile(), file.getName() + ".txt");
+ PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(
+ target)));
+ try {
+ int count = processFileOrDirectory(file, writer);
+ System.out.println(" (total " + count + " full thread dumps)");
+ } finally {
+ writer.close();
+ }
+ return target;
+ }
+
+ private static int processFileOrDirectory(File file, PrintWriter writer)
+ throws IOException {
+ if (file.isFile()) {
+ return processFile(file, writer);
+ }
+ int count = 0;
+ File[] list = file.listFiles();
+ if (list != null) {
+ for(File f : list) {
+ count += processFileOrDirectory(f, writer);
+ }
+ }
+ return count;
+ }
+
+ private static int processFile(File file, PrintWriter writer) throws
IOException {
+ Reader reader = null;
+ int count = 0;
+ try {
+ if (file.getName().endsWith(".DS_Store")) {
+ return 0;
+ }
+ int fullThreadDumps = 0;
+ if (file.getName().endsWith(".gz")) {
+ System.out.println("Extracting " + file.getAbsolutePath());
+ InputStream fileStream = new FileInputStream(file);
+ InputStream gzipStream = new GZIPInputStream(fileStream);
+ reader = new InputStreamReader(gzipStream);
+ } else {
+ System.out.println("Reading " + file.getAbsolutePath());
+ reader = new FileReader(file);
+ }
+ LineNumberReader in = new LineNumberReader(new BufferedReader(
+ reader));
+ while (true) {
+ String s;
+ try {
+ s = in.readLine();
+ } catch (EOFException e) {
+ // EOFException: Unexpected end of ZLIB input stream
+ break;
+ }
+ if (s == null) {
+ break;
+ }
+ if (s.startsWith("Full thread dump")) {
+ fullThreadDumps++;
+ }
+ writer.println(s);
+ }
+ if (fullThreadDumps > 0) {
+ count++;
+ System.out.println(" (contains " + fullThreadDumps + " full
thread dumps)");
+ }
+ } finally {
+ if(reader != null) {
+ reader.close();
+ }
+ }
+ return count;
+ }
+
+}
Added:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/threadDump/ThreadDumpCleaner.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/threadDump/ThreadDumpCleaner.java?rev=1750920&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/threadDump/ThreadDumpCleaner.java
(added)
+++
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/threadDump/ThreadDumpCleaner.java
Fri Jul 1 12:15:54 2016
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.threadDump;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+
+/**
+ * A tool that removes uninteresting lines from stack traces.
+ */
+public class ThreadDumpCleaner {
+
+ private static final String[] PATTERN_ARRAY = {
+ "\"Concurrent Mark-Sweep GC Thread\".*\n",
+
+ "\"Exception Catcher Thread\".*\n",
+
+ "JNI global references:.*\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State:.*\n\n",
+
+ "\".*?\".*\n\n",
+
+ "\\$\\$YJP\\$\\$",
+
+ "\"(Attach|Service|VM|GC|DestroyJavaVM|Signal|AWT|AppKit|C2 |Low Mem|"
+
+ "process reaper|YJPAgent-).*?\"(?s).*?\n\n",
+
+ " Locked ownable synchronizers:(?s).*?\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State: (TIMED_)?WAITING(?s).*?\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
+ "at sun.nio.ch.KQueueArrayWrapper.kevent0(?s).*?\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
+ "at java.io.FileInputStream.readBytes(?s).*?\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
+ "at sun.nio.ch.ServerSocketChannelImpl.accept(?s).*?\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
+ "at java.net.DualStackPlainSocketImpl.accept0(?s).*\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
+ "at sun.nio.ch.EPollArrayWrapper.epollWait(?s).*?\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
+ "at java.lang.Object.wait(?s).*?\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
+ "at java.net.PlainSocketImpl.socketAccept(?s).*?\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
+ "at java.net.SocketInputStream.socketRead0(?s).*?\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
+ "at
sun.nio.ch.WindowsSelectorImpl\\$SubSelector.poll0(?s).*?\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
+ "at sun.management.ThreadImpl.dumpThreads0(?s).*?\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
+ "at sun.misc.Unsafe.park(?s).*?\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
+ "at java.net.PlainSocketImpl.socketClose0(?s).*?\n\n",
+
+ "\".*?\".*?\n java.lang.Thread.State:.*\n\t" +
+ "at java.net.PlainSocketImpl.socketAvailable(?s).*?\n\n",
+
+ "<EndOfDump>\n\n",
+
+ };
+
+ private static ArrayList<Pattern> PATTERNS = new ArrayList<Pattern>();
+
+ static {
+ for (String s : PATTERN_ARRAY) {
+ PATTERNS.add(Pattern.compile(s));
+ }
+ }
+
+ public static File process(File file) throws IOException {
+ String fileName = file.getName();
+ if (fileName.endsWith(".txt")) {
+ fileName = fileName.substring(0, fileName.length() -
".txt".length());
+ }
+ File target = new File(file.getParentFile(), fileName +
".filtered.txt");
+ PrintWriter writer = new PrintWriter(new BufferedWriter(
+ new FileWriter(target)));
+ try {
+ processFile(file, writer);
+ } finally {
+ writer.close();
+ }
+ return target;
+ }
+
+ private static void processFile(File file, PrintWriter writer) throws
IOException {
+ LineNumberReader r = new LineNumberReader(new BufferedReader(
+ new FileReader(file)));
+ try {
+ process(r, writer);
+ } finally {
+ r.close();
+ }
+ }
+
+ private static void process(LineNumberReader reader, PrintWriter writer)
throws IOException {
+ StringBuilder buff = new StringBuilder();
+ while (true) {
+ String line = reader.readLine();
+ if (line == null) {
+ break;
+ }
+ buff.append(line).append('\n');
+ if (line.trim().length() == 0) {
+ writer.print(filter(buff.toString()));
+ buff = new StringBuilder();
+ }
+ }
+ writer.println(filter(buff.toString()));
+ }
+
+ private static String filter(String s) {
+ for (Pattern p : PATTERNS) {
+ s = p.matcher(s).replaceAll("");
+ }
+ return s;
+ }
+
+}