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