1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase;
19
20 import java.io.PrintWriter;
21 import java.io.StringWriter;
22 import java.lang.management.LockInfo;
23 import java.lang.management.ManagementFactory;
24 import java.lang.management.MonitorInfo;
25 import java.lang.management.ThreadInfo;
26 import java.lang.management.ThreadMXBean;
27 import java.text.DateFormat;
28 import java.text.SimpleDateFormat;
29 import java.util.Date;
30 import java.util.Locale;
31 import java.util.Map;
32
33 import org.junit.runner.notification.Failure;
34 import org.junit.runner.notification.RunListener;
35
36
37
38
39
40 public class TimedOutTestsListener extends RunListener {
41
42 static final String TEST_TIMED_OUT_PREFIX = "test timed out after";
43
44 private static String INDENT = " ";
45
46 private final PrintWriter output;
47
48 public TimedOutTestsListener() {
49 this.output = new PrintWriter(System.err);
50 }
51
52 public TimedOutTestsListener(PrintWriter output) {
53 this.output = output;
54 }
55
56 @Override
57 public void testFailure(Failure failure) throws Exception {
58 if (failure != null && failure.getMessage() != null
59 && failure.getMessage().startsWith(TEST_TIMED_OUT_PREFIX)) {
60 output.println("====> TEST TIMED OUT. PRINTING THREAD DUMP. <====");
61 output.println();
62 output.print(buildThreadDiagnosticString());
63 }
64 }
65
66 public static String buildThreadDiagnosticString() {
67 StringWriter sw = new StringWriter();
68 PrintWriter output = new PrintWriter(sw);
69
70 DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss,SSS");
71 output.println(String.format("Timestamp: %s", dateFormat.format(new Date())));
72 output.println();
73 output.println(buildThreadDump());
74
75 String deadlocksInfo = buildDeadlockInfo();
76 if (deadlocksInfo != null) {
77 output.println("====> DEADLOCKS DETECTED <====");
78 output.println();
79 output.println(deadlocksInfo);
80 }
81
82 return sw.toString();
83 }
84
85 static String buildThreadDump() {
86 StringBuilder dump = new StringBuilder();
87 Map<Thread, StackTraceElement[]> stackTraces = Thread.getAllStackTraces();
88 for (Map.Entry<Thread, StackTraceElement[]> e : stackTraces.entrySet()) {
89 Thread thread = e.getKey();
90 dump.append(String.format(
91 "\"%s\" %s prio=%d tid=%d %s\njava.lang.Thread.State: %s",
92 thread.getName(),
93 (thread.isDaemon() ? "daemon" : ""),
94 thread.getPriority(),
95 thread.getId(),
96 Thread.State.WAITING.equals(thread.getState()) ?
97 "in Object.wait()" : thread.getState().name().toLowerCase(Locale.ROOT),
98 Thread.State.WAITING.equals(thread.getState()) ?
99 "WAITING (on object monitor)" : thread.getState()));
100 for (StackTraceElement stackTraceElement : e.getValue()) {
101 dump.append("\n at ");
102 dump.append(stackTraceElement);
103 }
104 dump.append("\n");
105 }
106 return dump.toString();
107 }
108
109 static String buildDeadlockInfo() {
110 ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
111 long[] threadIds = threadBean.findMonitorDeadlockedThreads();
112 if (threadIds != null && threadIds.length > 0) {
113 StringWriter stringWriter = new StringWriter();
114 PrintWriter out = new PrintWriter(stringWriter);
115
116 ThreadInfo[] infos = threadBean.getThreadInfo(threadIds, true, true);
117 for (ThreadInfo ti : infos) {
118 printThreadInfo(ti, out);
119 printLockInfo(ti.getLockedSynchronizers(), out);
120 out.println();
121 }
122
123 out.close();
124 return stringWriter.toString();
125 } else {
126 return null;
127 }
128 }
129
130 private static void printThreadInfo(ThreadInfo ti, PrintWriter out) {
131
132 printThread(ti, out);
133
134
135 StackTraceElement[] stacktrace = ti.getStackTrace();
136 MonitorInfo[] monitors = ti.getLockedMonitors();
137 for (int i = 0; i < stacktrace.length; i++) {
138 StackTraceElement ste = stacktrace[i];
139 out.println(INDENT + "at " + ste.toString());
140 for (MonitorInfo mi : monitors) {
141 if (mi.getLockedStackDepth() == i) {
142 out.println(INDENT + " - locked " + mi);
143 }
144 }
145 }
146 out.println();
147 }
148
149 private static void printThread(ThreadInfo ti, PrintWriter out) {
150 out.print("\"" + ti.getThreadName() + "\"" + " Id="
151 + ti.getThreadId() + " in " + ti.getThreadState());
152 if (ti.getLockName() != null) {
153 out.print(" on lock=" + ti.getLockName());
154 }
155 if (ti.isSuspended()) {
156 out.print(" (suspended)");
157 }
158 if (ti.isInNative()) {
159 out.print(" (running in native)");
160 }
161 out.println();
162 if (ti.getLockOwnerName() != null) {
163 out.println(INDENT + " owned by " + ti.getLockOwnerName() + " Id="
164 + ti.getLockOwnerId());
165 }
166 }
167
168 private static void printLockInfo(LockInfo[] locks, PrintWriter out) {
169 out.println(INDENT + "Locked synchronizers: count = " + locks.length);
170 for (LockInfo li : locks) {
171 out.println(INDENT + " - " + li);
172 }
173 out.println();
174 }
175
176 }