1
18 package net.bull.javamelody.internal.web.html;
19
20 import java.io.IOException;
21 import java.io.Writer;
22 import java.text.DecimalFormat;
23 import java.text.MessageFormat;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Locale;
27
28 import net.bull.javamelody.internal.common.I18N;
29 import net.bull.javamelody.internal.common.Parameters;
30 import net.bull.javamelody.internal.model.JavaInformations;
31 import net.bull.javamelody.internal.model.MemoryInformations;
32 import net.bull.javamelody.internal.model.TomcatInformations;
33
34
38 public class HtmlJavaInformationsReport extends HtmlAbstractReport {
39 private static final String[] OS = { "linux", "windows", "mac", "solaris", "hp", "ibm", };
40 private static final String[] APPLICATION_SERVERS = { "tomcat", "glassfish", "jetty", "oracle",
41 "bea", "ibm", "jboss", "wildfly", };
42
43 private static final double MIN_VALUE = 0;
44 private static final double MAX_VALUE = 100;
45 private static final int PARTIAL_BLOCKS = 5;
46 private static final int FULL_BLOCKS = 10;
47 private static final double UNIT_SIZE = (MAX_VALUE - MIN_VALUE)
48 / (FULL_BLOCKS * PARTIAL_BLOCKS);
49
50 private final boolean noDatabase = Parameters.isNoDatabase();
51 private final DecimalFormat integerFormat = I18N.createIntegerFormat();
52 private final DecimalFormat decimalFormat = I18N.createPercentFormat();
53 private final List<JavaInformations> javaInformationsList;
54
55 HtmlJavaInformationsReport(List<JavaInformations> javaInformationsList, Writer writer) {
56 super(writer);
57 assert javaInformationsList != null && !javaInformationsList.isEmpty();
58
59 this.javaInformationsList = javaInformationsList;
60 }
61
62 @Override
63 void toHtml() throws IOException {
64 for (final JavaInformations javaInformations : javaInformationsList) {
65 writeSummary(javaInformations);
66 }
67
68 if (!noDatabase) {
69 write("<br/><br/>");
70 }
71 final String br = "<br/>";
72 if (javaInformationsList.get(0).getSessionCount() >= 0) {
73 write(br);
74 }
75 if (javaInformationsList.get(0).getSystemLoadAverage() >= 0) {
76
77 write(br);
78 }
79
80 writeln("<br/><br/><br/><br/> ");
81 writeShowHideLink("detailsJava", "#Details#");
82 writeln("<br/><br/><br/>");
83
84 writeln("<div id='detailsJava' class='displayNone'><div>");
85 final boolean repeatHost = javaInformationsList.size() > 1;
86 for (final JavaInformations javaInformations : javaInformationsList) {
87 writeDetails(javaInformations, repeatHost);
88 }
89 writeln("</div></div>");
90 }
91
92 private void writeSummary(JavaInformations javaInformations) throws IOException {
93 final String lineEnd = "</td> </tr>";
94 final String columnAndLineEnd = "</td><td>" + lineEnd;
95 writeln("<table align='left' border='0' summary='#Informations_systemes#'>");
96 writeln("<tr><td>#Host#: </td><td><b>" + javaInformations.getHost() + "</b>" + lineEnd);
97 final MemoryInformations memoryInformations = javaInformations.getMemoryInformations();
98 final long usedMemory = memoryInformations.getUsedMemory();
99 final long maxMemory = memoryInformations.getMaxMemory();
100 write("<tr><td>#memoire_utilisee#: </td><td>");
101 writeGraph("usedMemory", integerFormat.format(usedMemory / 1024 / 1024));
102 writeln(" #Mo# / " + integerFormat.format(maxMemory / 1024 / 1024)
103 + " #Mo# </td><td>");
104 writeln(toBarWithAlert(memoryInformations.getUsedMemoryPercentage(), "-Xmx"));
105 writeln(lineEnd);
106 if (javaInformations.getSessionCount() >= 0) {
107 write("<tr><td>#nb_sessions_http#: </td><td>");
108 writeGraph("httpSessions", integerFormat.format(javaInformations.getSessionCount()));
109 writeln(columnAndLineEnd);
110 }
111 write("<tr><td>#nb_threads_actifs#<br/>(#Requetes_http_en_cours#): </td><td>");
112 writeGraph("activeThreads", integerFormat.format(javaInformations.getActiveThreadCount()));
113 writeln(columnAndLineEnd);
114 if (!noDatabase) {
115 write("<tr><td>#nb_connexions_actives#: </td><td>");
116 writeGraph("activeConnections",
117 integerFormat.format(javaInformations.getActiveConnectionCount()));
118 writeln(columnAndLineEnd);
119 final int usedConnectionCount = javaInformations.getUsedConnectionCount();
120 final int maxConnectionCount = javaInformations.getMaxConnectionCount();
121 write("<tr><td>#nb_connexions_utilisees#<br/>(#ouvertes#): </td><td>");
122 writeGraph("usedConnections", integerFormat.format(usedConnectionCount));
123 if (maxConnectionCount > 0) {
124 writeln(" / " + integerFormat.format(maxConnectionCount)
125 + " </td><td>");
126 writeln(toBarWithAlert(javaInformations.getUsedConnectionPercentage(), null));
127 }
128 writeln(lineEnd);
129 }
130 if (javaInformations.getSystemLoadAverage() >= 0) {
131 write("<tr><td>#Charge_systeme#</td><td>");
132 writeGraph("systemLoad", decimalFormat.format(javaInformations.getSystemLoadAverage()));
133 writeln(columnAndLineEnd);
134 }
135 if (javaInformations.getSystemCpuLoad() >= 0) {
136 write("<tr><td>#systemCpuLoad#</td><td>");
137 writeGraph("systemCpuLoad", decimalFormat.format(javaInformations.getSystemCpuLoad()));
138 writeln(" </td><td>");
139 writeln(toBarWithAlert(javaInformations.getSystemCpuLoad(), null));
140 writeln(lineEnd);
141 }
142 writeln("</table>");
143 }
144
145 private void writeDetails(JavaInformations javaInformations, boolean repeatHost)
146 throws IOException {
147 final String columnEnd = "</td></tr>";
148 writeln("<table align='left' border='0' summary='#Details_systeme#'>");
149 if (repeatHost) {
150 writeln("<tr><td>#Host#: </td><td><b>" + javaInformations.getHost() + "</b>"
151 + columnEnd);
152 }
153 writeln("<tr><td>#OS#: </td><td>");
154 final String osIconName = getOSIconName(javaInformations.getOS());
155 if (osIconName != null) {
156 writeln("<img src='?resource=servers/" + osIconName + "' alt='#OS#'/>");
157 }
158 writeln(javaInformations.getOS() + " (" + javaInformations.getAvailableProcessors()
159 + " #coeurs#)" + columnEnd);
160 writeln("<tr><td>#Java#: </td><td>" + javaInformations.getJavaVersion() + columnEnd);
161 write("<tr><td>#JVM#: </td><td>" + javaInformations.getJvmVersion());
162 if (javaInformations.getJvmVersion().contains("Client")) {
163 write(" <img src='?resource=alert.png' alt=\"#Client_JVM#\" title=\"#Client_JVM#\"/>");
164 }
165 writeln(columnEnd);
166 writeln("<tr><td>#PID#: </td><td>" + javaInformations.getPID() + columnEnd);
167 final long unixOpenFileDescriptorCount = javaInformations.getUnixOpenFileDescriptorCount();
168 if (unixOpenFileDescriptorCount >= 0) {
169 final long unixMaxFileDescriptorCount = javaInformations
170 .getUnixMaxFileDescriptorCount();
171 write("<tr><td>#nb_fichiers#</td><td>");
172 writeGraph("fileDescriptors", integerFormat.format(unixOpenFileDescriptorCount));
173 writeln(" / " + integerFormat.format(unixMaxFileDescriptorCount)
174 + " ");
175 writeln(toBarWithAlert(javaInformations.getUnixOpenFileDescriptorPercentage(), null));
176 writeln(columnEnd);
177 }
178 writeServerInfoAndContextPath(javaInformations);
179 writeln("<tr><td>#Demarrage#: </td><td>"
180 + I18N.createDateAndTimeFormat().format(javaInformations.getStartDate())
181 + columnEnd);
182
183 write("<tr><td valign='top'>#Arguments_JVM#: </td><td>");
184
185 writeDirectly(htmlEncodeButNotSpace(javaInformations.getJvmArguments()) + columnEnd);
186 writeln("");
187
188 if (javaInformations.getSessionCount() >= 0) {
189 write("<tr><td>#httpSessionsMeanAge#: </td><td>");
190 writeGraph("httpSessionsMeanAge",
191 integerFormat.format(javaInformations.getSessionMeanAgeInMinutes()));
192 writeln(columnEnd);
193 }
194
195 writeTomcatInformations(javaInformations.getTomcatInformationsList());
196
197 writeMemoryInformations(javaInformations.getMemoryInformations());
198
199
200 writeln("<tr><td>#Free_disk_space#: </td><td>"
201 + integerFormat.format(javaInformations.getFreeDiskSpaceInTemp() / 1024 / 1024)
202 + " #Mo# " + columnEnd);
203 writeln("<tr><td>#Usable_disk_space#: </td><td>"
204 + integerFormat.format(javaInformations.getUsableDiskSpaceInTemp() / 1024 / 1024)
205 + " #Mo# " + columnEnd);
206
207 writeDatabaseVersionAndDataSourceDetails(javaInformations);
208
209 writeln("<tr><td valign='top'><div class='noPrint'>#Dependencies#: </div></td><td>");
210 writeDependencies(javaInformations);
211 writeln(columnEnd);
212
213 writeln("</table>");
214 }
215
216 private void writeServerInfoAndContextPath(JavaInformations javaInformations)
217 throws IOException {
218 final String serverInfo = javaInformations.getServerInfo();
219 if (serverInfo != null) {
220 final String columnEnd = " </td></tr>";
221 writeln("<tr><td>#Serveur#: </td><td>");
222 final String applicationServerIconName = getApplicationServerIconName(serverInfo);
223 if (applicationServerIconName != null) {
224 writeln("<img src='?resource=servers/" + applicationServerIconName
225 + "' alt='#Serveur#'/>");
226 }
227 writeDirectly(serverInfo + columnEnd);
228 writeln("<tr><td>#Contexte_webapp#: </td><td>" + javaInformations.getContextPath()
229 + columnEnd);
230 }
231 }
232
233 private void writeDatabaseVersionAndDataSourceDetails(JavaInformations javaInformations)
234 throws IOException {
235 final String columnEnd = "</td></tr>";
236 if (!noDatabase && javaInformations.getDataBaseVersion() != null) {
237 writeln("<tr><td valign='top'>#Base_de_donnees#: </td><td>");
238
239 writeDirectly(htmlEncodeButNotSpace(javaInformations.getDataBaseVersion()));
240 writeln(columnEnd);
241 }
242 if (javaInformations.getDataSourceDetails() != null) {
243 writeln("<tr><td valign='top'>#DataSource_jdbc#: </td><td>");
244
245 writeDirectly(htmlEncodeButNotSpace(javaInformations.getDataSourceDetails()));
246 writeDirectly(
247 "<a href='http:
248 + " class='noPrint' target='_blank'>DataSource reference</a>");
249
250
251
252 writeln(columnEnd);
253 }
254 }
255
256 public static String getOSIconName(String os) {
257 final String tmp = os.toLowerCase(Locale.ENGLISH);
258 for (final String anOS : OS) {
259 if (tmp.contains(anOS)) {
260 return anOS + ".png";
261 }
262 }
263 return null;
264 }
265
266 public static String getApplicationServerIconName(String appServer) {
267 final String tmp = appServer.toLowerCase(Locale.ENGLISH);
268 for (final String applicationServer : APPLICATION_SERVERS) {
269 if (tmp.contains(applicationServer)) {
270 return applicationServer + ".png";
271 }
272 }
273 return null;
274 }
275
276 private void writeTomcatInformations(List<TomcatInformations> tomcatInformationsList)
277 throws IOException {
278 final List<TomcatInformations> list = new ArrayList<>();
279 for (final TomcatInformations tomcatInformations : tomcatInformationsList) {
280 if (tomcatInformations.getRequestCount() > 0) {
281 list.add(tomcatInformations);
282 }
283 }
284 final boolean onlyOne = list.size() == 1;
285 for (final TomcatInformations tomcatInformations : list) {
286 writeDirectly("<tr><td valign='top'>Tomcat "
287 + htmlEncodeButNotSpace(tomcatInformations.getName()) + ": </td><td>");
288
289 final int currentThreadsBusy = tomcatInformations.getCurrentThreadsBusy();
290 writeln("#busyThreads# = ");
291 if (onlyOne) {
292 writeGraph("tomcatBusyThreads", integerFormat.format(currentThreadsBusy));
293 } else {
294 writeln(integerFormat.format(currentThreadsBusy));
295 }
296 writeln(" / " + integerFormat.format(tomcatInformations.getMaxThreads()));
297 writeln(" ");
298 writeln(toBarWithAlert(100d * currentThreadsBusy / tomcatInformations.getMaxThreads(),
299 null));
300 writeln("<br/>#bytesReceived# = ");
301 if (onlyOne) {
302 writeGraph("tomcatBytesReceived",
303 integerFormat.format(tomcatInformations.getBytesReceived()));
304 } else {
305 writeln(integerFormat.format(tomcatInformations.getBytesReceived()));
306 }
307 writeln("<br/>#bytesSent# = ");
308 if (onlyOne) {
309 writeGraph("tomcatBytesSent",
310 integerFormat.format(tomcatInformations.getBytesSent()));
311 } else {
312 writeln(integerFormat.format(tomcatInformations.getBytesSent()));
313 }
314 writeln("<br/>#requestCount# = ");
315 writeln(integerFormat.format(tomcatInformations.getRequestCount()));
316 writeln("<br/>#errorCount# = ");
317 writeln(integerFormat.format(tomcatInformations.getErrorCount()));
318 writeln("<br/>#processingTime# = ");
319 writeln(integerFormat.format(tomcatInformations.getProcessingTime()));
320 writeln("<br/>#maxProcessingTime# = ");
321 writeln(integerFormat.format(tomcatInformations.getMaxTime()));
322 writeln("</td> </tr>");
323 }
324 }
325
326 private void writeMemoryInformations(MemoryInformations memoryInformations) throws IOException {
327 final String columnEnd = "</td></tr>";
328 final String memoryDetails = memoryInformations.getMemoryDetails();
329 writeln("<tr><td valign='top'>#Gestion_memoire#: </td><td>"
330 + htmlEncodeButNotSpace(memoryDetails).replace(" Mo", " #Mo#") + columnEnd);
331
332 final long usedPermGen = memoryInformations.getUsedPermGen();
333 if (usedPermGen > 0) {
334
335 final long maxPermGen = memoryInformations.getMaxPermGen();
336 writeln("<tr><td>#Memoire_Perm_Gen#: </td><td>"
337 + integerFormat.format(usedPermGen / 1024 / 1024) + " #Mo#");
338 if (maxPermGen > 0) {
339 writeln(" / " + integerFormat.format(maxPermGen / 1024 / 1024)
340 + " #Mo# ");
341 writeln(toBarWithAlert(memoryInformations.getUsedPermGenPercentage(),
342 "-XX:MaxPermSize"));
343 }
344 writeln(columnEnd);
345 }
346 }
347
348 private void writeDependencies(JavaInformations javaInformations) throws IOException {
349 writeln("<a href='?part=dependencies' class='noPrint'>");
350 writeln("<img src='?resource=beans.png' width='14' height='14' alt='#Dependencies#'/> #Dependencies#</a>");
351 if (javaInformations.doesPomXmlExists() && Parameters.isSystemActionsEnabled()) {
352 writeln(" ");
353 writeln("<a href='?part=pom.xml' class='noPrint'>");
354 writeln("<img src='?resource=xml.png' width='14' height='14' alt=\"#pom.xml#\"/> #pom.xml#</a>");
355 }
356 }
357
358 private void writeGraph(String graph, String value) throws IOException {
359 if (javaInformationsList.size() > 1) {
360 write(value);
361 return;
362 }
363 final String id = "id" + graph;
364
365 write("<a class='tooltip replaceImage' href='?part=graph&graph=");
366 write(graph);
367 write("' data-img-id='");
368 write(id);
369 write("' data-img-src='?graph=");
370 write(graph);
371 write("&width=100&height=50'>");
372
373 write("<em><img src='?resource=systeminfo.png' id='");
374 write(id);
375 write("' alt='graph'/></em>");
376
377 writeDirectly(value);
378 write("</a>");
379 }
380
381
382 static String toBar(double percentValue) {
383 final double myPercent = Math.max(Math.min(percentValue, 100d), 0d);
384 final StringBuilder sb = new StringBuilder();
385 final String body = "<img src=''?resource=bar/rb_{0}.gif'' alt=''+'' title=''"
386 + I18N.createPercentFormat().format(myPercent) + "%'' />";
387 final int fullBlockCount = (int) Math.floor(myPercent / (UNIT_SIZE * PARTIAL_BLOCKS));
388 final int partialBlockIndex = (int) Math
389 .floor((myPercent - fullBlockCount * UNIT_SIZE * PARTIAL_BLOCKS) / UNIT_SIZE);
390
391 sb.append(MessageFormat.format(body,
392 fullBlockCount > 0 || partialBlockIndex > 0 ? "a" : "a0"));
393
394 final String fullBody = MessageFormat.format(body, PARTIAL_BLOCKS);
395 for (int i = 0; i < fullBlockCount; i++) {
396 sb.append(fullBody);
397 }
398
399 if (partialBlockIndex > 0) {
400 final String partialBody = MessageFormat.format(body, partialBlockIndex);
401 sb.append(partialBody);
402 }
403
404 final int emptyBlocks = FULL_BLOCKS - fullBlockCount - (partialBlockIndex > 0 ? 1 : 0);
405 final String emptyBody = MessageFormat.format(body, 0);
406 for (int i = 0; i < emptyBlocks; i++) {
407 sb.append(emptyBody);
408 }
409
410 sb.append(MessageFormat.format(body, fullBlockCount == FULL_BLOCKS ? "b" : "b0"));
411 return sb.toString();
412 }
413
414 static String toBarWithAlert(double percentValue, String configurationDetail) {
415 String result = toBar(percentValue);
416 if (percentValue >= JavaInformations.HIGH_USAGE_THRESHOLD_IN_PERCENTS) {
417 String message = getString("High_usage");
418 if (configurationDetail != null) {
419 message += " (" + configurationDetail + ')';
420 }
421 result += " <img src='?resource=alert.png' alt=\"" + message
422 + "\" title=\"" + message + "\"/>";
423 }
424 return result;
425 }
426 }
427