1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.monitor.integration;
20
21 import java.lang.management.ManagementFactory;
22 import java.lang.management.ThreadInfo;
23 import java.lang.management.ThreadMXBean;
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Method;
26 import java.security.Security;
27 import java.util.HashMap;
28 import java.util.Map;
29
30 import org.eclipse.jetty.util.annotation.ManagedObject;
31 import org.eclipse.jetty.util.annotation.ManagedOperation;
32
33
34
35
36
37
38
39
40 @ManagedObject("Java Monitoring Tools")
41 public class JavaMonitorTools
42 {
43 private static final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
44
45 private static Method findDeadlockMethod = null;
46
47 static
48 {
49 try
50 {
51 findDeadlockMethod = ThreadMXBean.class.getMethod("findDeadlockedThreads");
52 }
53 catch (Exception ignored)
54 {
55
56 try
57 {
58 findDeadlockMethod = ThreadMXBean.class.getMethod("findMonitorDeadlockedThreads");
59 }
60 catch (SecurityException e)
61 {
62 e.printStackTrace();
63 }
64 catch (NoSuchMethodException e)
65 {
66 e.printStackTrace();
67 }
68 }
69 }
70
71 private ThreadInfo[] findDeadlock()
72 throws IllegalAccessException, InvocationTargetException
73 {
74 final long[] threadIds = (long[])findDeadlockMethod.invoke(threadMXBean,(Object[])null);
75
76 if (threadIds == null || threadIds.length < 1)
77 {
78
79 return null;
80 }
81
82 final ThreadInfo[] threads = threadMXBean.getThreadInfo(threadIds,Integer.MAX_VALUE);
83 return threads;
84 }
85 @ManagedOperation(value="Detailed report on the deadlocked threads.", impact="ACTION_INFO")
86 public String getDeadlockStacktraces()
87 {
88 try
89 {
90 final ThreadInfo[] threads = findDeadlock();
91 if (threads == null)
92 {
93
94 return null;
95 }
96
97 return stacktraces(threads,0);
98 }
99 catch (Exception e)
100 {
101 return e.getMessage();
102 }
103 }
104
105 private static final int MAX_STACK = 10;
106
107 private String stacktraces(final ThreadInfo[] threads, final int i)
108 {
109 if (i >= threads.length)
110 {
111 return "";
112 }
113 final ThreadInfo thread = threads[i];
114
115 final StringBuilder trace = new StringBuilder();
116 for (int stack_i = 0; stack_i < Math.min(thread.getStackTrace().length,MAX_STACK); stack_i++)
117 {
118 if (stack_i == (MAX_STACK - 1))
119 {
120 trace.append(" ...");
121 }
122 else
123 {
124 trace.append(" at ").append(thread.getStackTrace()[stack_i]).append("\n");
125 }
126 }
127
128 return "\"" + thread.getThreadName() + "\", id " + thread.getThreadId() + " is " + thread.getThreadState() + " on " + thread.getLockName()
129 + ", owned by " + thread.getLockOwnerName() + ", id " + thread.getLockOwnerId() + "\n" + trace + "\n\n" + stacktraces(threads,i + 1);
130 }
131
132
133
134
135
136
137 private long lastSampled = 0L;
138
139 private final Map<Thread.State, Integer> states = new HashMap<Thread.State, Integer>();
140
141 @ManagedOperation(value="Number of Blocked Threads")
142 public int getThreadsBlocked()
143 {
144 sampleThreads();
145
146 return states.get(Thread.State.BLOCKED);
147 }
148
149 @ManagedOperation(value="Number of New Threads", impact="ACTION_INFO")
150 public int getThreadsNew()
151 {
152 sampleThreads();
153
154 return states.get(Thread.State.NEW);
155 }
156
157 @ManagedOperation(value="Number of Terminated Threads", impact="ACTION_INFO")
158 public int getThreadsTerminated()
159 {
160 sampleThreads();
161
162 return states.get(Thread.State.TERMINATED);
163 }
164
165 @ManagedOperation(value="Number of Sleeping and Waiting threads")
166 public int getThreadsTimedWaiting()
167 {
168 sampleThreads();
169
170 return states.get(Thread.State.TIMED_WAITING);
171 }
172
173 @ManagedOperation(value="Number of Waiting Threads", impact="ACTION_INFO")
174 public int getThreadsWaiting()
175 {
176 sampleThreads();
177
178 return states.get(Thread.State.WAITING);
179 }
180
181 @ManagedOperation(value="Number of Runnable Threads", impact="ACTION_INFO")
182 public int getThreadsRunnable()
183 {
184 sampleThreads();
185
186 return states.get(Thread.State.RUNNABLE);
187 }
188
189 private synchronized void sampleThreads()
190 {
191 if ((lastSampled + 50L) < System.currentTimeMillis())
192 {
193 lastSampled = System.currentTimeMillis();
194 for (final Thread.State state : Thread.State.values())
195 {
196 states.put(state,0);
197 }
198
199 for (final ThreadInfo thread : threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds()))
200 {
201 if (thread != null)
202 {
203 final Thread.State state = thread.getThreadState();
204 states.put(state,states.get(state) + 1);
205 }
206 else
207 {
208 states.put(Thread.State.TERMINATED,states.get(Thread.State.TERMINATED) + 1);
209 }
210 }
211 }
212 }
213
214 private static final String POLICY = "sun.net.InetAddressCachePolicy";
215
216 @ManagedOperation(value="Amount of time successful DNS queries are cached for.")
217 public int getCacheSeconds() throws ClassNotFoundException,
218 IllegalAccessException, InvocationTargetException,
219 NoSuchMethodException {
220 final Class policy = Class.forName(POLICY);
221 final Object returnValue = policy.getMethod("get", (Class[]) null)
222 .invoke(null, (Object[]) null);
223 Integer seconds = (Integer) returnValue;
224
225 return seconds.intValue();
226 }
227
228 @ManagedOperation(value="Amount of time failed DNS queries are cached for")
229 public int getCacheNegativeSeconds() throws ClassNotFoundException,
230 IllegalAccessException, InvocationTargetException,
231 NoSuchMethodException {
232 final Class policy = Class.forName(POLICY);
233 final Object returnValue = policy.getMethod("getNegative",
234 (Class[]) null).invoke(null, (Object[]) null);
235 Integer seconds = (Integer) returnValue;
236
237 return seconds.intValue();
238 }
239
240 private static final String DEFAULT = "default";
241
242 private static final String SECURITY = "security";
243
244 private static final String SYSTEM = "system";
245
246 private static final String BOTH = "both";
247
248 private static final String SECURITY_TTL = "networkaddress.cache.ttl";
249
250 private static final String SYSTEM_TTL = "sun.net.inetaddr.ttl";
251
252 private static final String SECURITY_NEGATIVE_TTL = "networkaddress.cache.negative.ttl";
253
254 private static final String SYSTEM_NEGATIVE_TTL = "sun.net.inetaddr.negative.ttl";
255
256 @ManagedOperation(value="Cache policy for successful DNS lookups was changed from the hard-coded default")
257 public String getCacheTweakedFrom() {
258 if (Security.getProperty(SECURITY_TTL) != null) {
259 if (System.getProperty(SYSTEM_TTL) != null) {
260 return BOTH;
261 }
262
263 return SECURITY;
264 }
265
266 if (System.getProperty(SYSTEM_TTL) != null) {
267 return SYSTEM;
268 }
269
270 return DEFAULT;
271 }
272
273 @ManagedOperation(value="Cache policy for failed DNS lookups was changed from the hard-coded default")
274 public String getCacheNegativeTweakedFrom() {
275 if (Security.getProperty(SECURITY_NEGATIVE_TTL) != null) {
276 if (System.getProperty(SYSTEM_NEGATIVE_TTL) != null) {
277 return BOTH;
278 }
279
280 return SECURITY;
281 }
282
283 if (System.getProperty(SYSTEM_NEGATIVE_TTL) != null) {
284 return SYSTEM;
285 }
286
287 return DEFAULT;
288 }
289 }