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