Skip to content

Commit

Permalink
display webapp version at the top and display drop-down to choose per…
Browse files Browse the repository at this point in the history
…iod based on webapp versions
  • Loading branch information
evernat committed Apr 12, 2017
1 parent b50d97c commit d61e65f
Show file tree
Hide file tree
Showing 11 changed files with 254 additions and 11 deletions.
90 changes: 90 additions & 0 deletions javamelody-core/src/main/java/net/bull/javamelody/Collector.java
Expand Up @@ -18,7 +18,13 @@
package net.bull.javamelody;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
Expand All @@ -28,7 +34,9 @@
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import net.bull.javamelody.Counter.CounterRequestContextComparator;
Expand All @@ -39,7 +47,10 @@
* @author Emeric Vernat
*/
class Collector { // NOPMD
private static final String VERSIONS_FILENAME = "versions.properties";
private static final String VERSIONS_DATE_PATTERN = "yyyy/MM/dd";
private static final long NOT_A_NUMBER = Long.MIN_VALUE;

// période entre 2 collectes en milli-secondes
private final int periodMillis;
private final String application;
Expand Down Expand Up @@ -68,6 +79,10 @@ class Collector { // NOPMD
private Date lastDateOfDeletedObsoleteFiles = new Date();
private boolean stopped;
private final boolean noDatabase = Parameters.isNoDatabase();
/**
* Les versions de l'applications avec pour chacune la date de déploiement.
*/
private final Map<String, Date> datesByWebappVersions;

/**
* Constructeur.
Expand Down Expand Up @@ -122,6 +137,8 @@ class Collector { // NOPMD
LOG.warn("exception while reading counters data from files in "
+ Parameters.getStorageDirectory(application), e);
}

datesByWebappVersions = readDatesByWebappVersions();
}

/**
Expand All @@ -147,6 +164,10 @@ List<SampledMethod> getHotspots() {
return samplingProfiler.getHotspots(1000);
}

Map<String, Date> getDatesByWebappVersions() {
return Collections.unmodifiableMap(datesByWebappVersions);
}

/**
* @return La liste des counters de ce collector
*/
Expand Down Expand Up @@ -348,6 +369,14 @@ private long collect(List<JavaInformations> javaInformationsList) throws IOExcep
}
}

if (!javaInformationsList.isEmpty()) {
final String webappVersion = javaInformationsList.get(0).getWebappVersion();
if (webappVersion != null && !datesByWebappVersions.containsKey(webappVersion)) {
addWebappVersion(webappVersion);
datesByWebappVersions.put(webappVersion, new Date());
}
}

return memorySize;
}
}
Expand Down Expand Up @@ -917,6 +946,67 @@ private Collection<JRobin> getDisplayedJRobins(Collection<JRobin> jrobins) {
return Collections.unmodifiableCollection(displayedJRobins);
}

@SuppressWarnings("unchecked")
private Map<String, Date> readDatesByWebappVersions() {
final Map<String, Date> result = new HashMap<String, Date>();
final File storageDirectory = Parameters.getStorageDirectory(application);
final File versionsFile = new File(storageDirectory, VERSIONS_FILENAME);
if (versionsFile.exists()) {
final Properties versionsProperties = new Properties();
try {
final InputStream input = new FileInputStream(versionsFile);
try {
versionsProperties.load(input);
} finally {
input.close();
}
final List<String> propertyNames = (List<String>) Collections
.list(versionsProperties.propertyNames());
final SimpleDateFormat dateFormat = new SimpleDateFormat(VERSIONS_DATE_PATTERN,
Locale.US);
for (final String version : propertyNames) {
try {
final Date date = dateFormat.parse(versionsProperties.getProperty(version));
result.put(version, date);
} catch (final ParseException e) {
continue;
}
}
} catch (final IOException e) {
// lecture échouée, tant pis
LOG.warn("exception while reading versions in " + versionsFile, e);
}
}
return result;
}

private void addWebappVersion(String webappVersion) throws IOException {
assert webappVersion != null && !webappVersion.isEmpty();
final File storageDirectory = Parameters.getStorageDirectory(application);
final File versionsFile = new File(storageDirectory, VERSIONS_FILENAME);
final Properties versionsProperties = new Properties();
if (versionsFile.exists()) {
final InputStream input = new FileInputStream(versionsFile);
try {
versionsProperties.load(input);
} finally {
input.close();
}
}
assert versionsProperties.getProperty(webappVersion) == null;

final SimpleDateFormat dateFormat = new SimpleDateFormat(VERSIONS_DATE_PATTERN, Locale.US);
versionsProperties.setProperty(webappVersion, dateFormat.format(new Date()));

final OutputStream output = new FileOutputStream(versionsFile);
try {
versionsProperties.store(output, "Application deployments with versions and dates");
} finally {
output.close();
}
LOG.debug("New application version added: " + webappVersion);
}

/**
* Purge les données pour un compteur à partir de son nom.
* @param counterName Nom du compteur
Expand Down
Expand Up @@ -335,6 +335,7 @@ private void logSystemInformationsAndParameters() {
LOG.debug("JavaMelody classes loaded from: " + location);
}
LOG.debug("Application type: " + applicationType);
LOG.debug("Application version: " + MavenArtifact.getWebappVersion());
LOG.debug("Host: " + Parameters.getHostName() + '@' + Parameters.getHostAddress());
for (final Parameter parameter : Parameter.values()) {
final String value = Parameters.getParameter(parameter);
Expand Down
119 changes: 108 additions & 11 deletions javamelody-core/src/main/java/net/bull/javamelody/HtmlCoreReport.java
Expand Up @@ -22,7 +22,11 @@
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
Expand All @@ -48,16 +52,49 @@ class HtmlCoreReport extends HtmlAbstractReport {
private final long start = System.currentTimeMillis();
private final Map<String, String> menuTextsByAnchorName = new LinkedHashMap<String, String>();

private static class MapValueComparator<K, V extends Comparable<V>>
implements Comparator<Map.Entry<K, V>> {
MapValueComparator() {
super();
}

@Override
public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
return o1.getValue().compareTo(o2.getValue());
}
}

private static class HtmlForms extends HtmlAbstractReport {
private static final Comparator<Map.Entry<String, Date>> MAP_VALUE_COMPARATOR = Collections
.reverseOrder(new MapValueComparator<String, Date>());

HtmlForms(Writer writer) {
super(writer);
}

void writeCustomPeriodLink(Range range, String graphName, String part) throws IOException {
void writeCustomPeriodLinks(Map<String, Date> datesByWebappVersions, Range currentRange,
String graphName, String part) throws IOException {
writeln("<a href=\"javascript:showHide('customPeriod');document.customPeriodForm.startDate.focus();\" ");
final String linkLabel = getString("personnalisee");
writeln("title='" + getFormattedString("Choisir_periode", linkLabel) + "'>");
writeln("title='" + getFormattedString("Choisir_periode", getString("personnalisee"))
+ "'>");
writeln("<img src='?resource=calendar.png' alt='#personnalisee#' /> #personnalisee#</a>");

if (!datesByWebappVersions.isEmpty()) {
writeln("&nbsp;<a href=\"javascript:showHide('deploymentPeriod');\" ");
writeln("title='"
+ getFormattedString("Choisir_periode", getString("par_deploiement"))
+ "'>");
writeln("<img src='?resource=calendar.png' alt='#par_deploiement#' /> #par_deploiement#</a>");
}

writeCustomPeriodDiv(currentRange, graphName, part);
if (!datesByWebappVersions.isEmpty()) {
writeDeploymentPeriodDiv(datesByWebappVersions, currentRange, graphName, part);
}
}

private void writeCustomPeriodDiv(Range currentRange, String graphName, String part)
throws IOException {
writeln("<div id='customPeriod' style='display: none;'>");
writeln(SCRIPT_BEGIN);
writeln("function validateCustomPeriodForm() {");
Expand All @@ -80,12 +117,12 @@ void writeCustomPeriodLink(Range range, String graphName, String part) throws IO
}
writeln("<form name='customPeriodForm' method='get' action='' onsubmit='return validateCustomPeriodForm();'>");
writeln("<br/><b>#startDate#</b>&nbsp;&nbsp;<input type='text' size='10' name='startDate' ");
if (range.getStartDate() != null) {
writeln("value='" + dateFormat.format(range.getStartDate()) + '\'');
if (currentRange.getStartDate() != null) {
writeln("value='" + dateFormat.format(currentRange.getStartDate()) + '\'');
}
writeln("/>&nbsp;&nbsp;<b>#endDate#</b>&nbsp;&nbsp;<input type='text' size='10' name='endDate' ");
if (range.getEndDate() != null) {
writeln("value='" + dateFormat.format(range.getEndDate()) + '\'');
if (currentRange.getEndDate() != null) {
writeln("value='" + dateFormat.format(currentRange.getEndDate()) + '\'');
}
writeln("/>&nbsp;&nbsp;");
writeDirectly('(' + dateFormatPattern + ')');
Expand All @@ -99,6 +136,54 @@ void writeCustomPeriodLink(Range range, String graphName, String part) throws IO
writeln(END_DIV);
}

private void writeDeploymentPeriodDiv(Map<String, Date> datesByWebappVersions,
Range currentRange, String graphName, String part) throws IOException {
writeln("<div id='deploymentPeriod' style='display: none;'>");
writeln("<br/>");
final DateFormat dateFormat = I18N.createDateFormat();
final String currentRangeValue = currentRange.getValue();
final String startDateLabel = I18N.getString("startDate")
.toLowerCase(I18N.getCurrentLocale());
final String endDateLabel = I18N.getString("endDate");
writeln("<form name='deploymentPeriodForm' method='get' action=''>");
writeln("<br/><b>#Version#</b>&nbsp;&nbsp;");
writeln("<select name='period' onchange='document.deploymentPeriodForm.submit();'>");
writeDirectly("<option>&nbsp;</option>");
// on doit retrier les versions ici, notamment s'il y en a une ajoutée à la fin
final List<Map.Entry<String, Date>> orderedVersionsByDate = new ArrayList<Map.Entry<String, Date>>(
datesByWebappVersions.entrySet());
Collections.sort(orderedVersionsByDate, MAP_VALUE_COMPARATOR);
String previousDate = null;
for (final Map.Entry<String, Date> entry : orderedVersionsByDate) {
final String version = entry.getKey();
final String date = dateFormat.format(entry.getValue());
final String label;
if (previousDate == null) {
previousDate = dateFormat.format(new Date());
label = version + ' ' + startDateLabel + ' ' + date;
} else {
label = version + ' ' + startDateLabel + ' ' + date + ' ' + endDateLabel + ' '
+ previousDate;
}
final String rangeValue = date + Range.CUSTOM_PERIOD_SEPARATOR + previousDate;
writeDirectly("<option value='" + rangeValue + "'");
if (rangeValue.equals(currentRangeValue)) {
writeDirectly(" selected='selected'");
}
writeDirectly(">");
writeDirectly(htmlEncodeButNotSpace(label));
writeDirectly("</option>");
previousDate = date;
}
writeln("</select><br/><br/>");
if (graphName != null) {
writeln("<input type='hidden' name='part' value='" + part + "'/>");
writeln("<input type='hidden' name='graph' value='" + urlEncode(graphName) + "'/>");
}
writeln("</form><br/>");
writeln(END_DIV);
}

void writeAddAndRemoveApplicationLinks(String currentApplication) throws IOException {
if (currentApplication == null) {
writeln("<div align='center'><h3>#add_application#</h3>");
Expand Down Expand Up @@ -265,9 +350,19 @@ private void writeSummary() throws IOException {
writeDirectly(getFormattedString("Statistiques_sans_depuis", javaMelodyUrl,
I18N.getCurrentDateAndTime(), collector.getApplication()));
}
if (javaInformationsList.get(0).getContextDisplayName() != null) {
writeDirectly(htmlEncodeButNotSpace(
" (" + javaInformationsList.get(0).getContextDisplayName() + ')'));
final String contextDisplayName = javaInformationsList.get(0).getContextDisplayName();
final String webappVersion = javaInformationsList.get(0).getWebappVersion();
if (contextDisplayName != null) {
writeDirectly(" (");
writeDirectly(htmlEncodeButNotSpace(contextDisplayName));
if (webappVersion != null) {
writeDirectly(", " + htmlEncodeButNotSpace(webappVersion));
}
writeDirectly(")");
} else if (webappVersion != null) {
writeDirectly(" (");
writeDirectly(htmlEncodeButNotSpace(webappVersion));
writeDirectly(")");
}
writeln("");
}
Expand Down Expand Up @@ -889,7 +984,9 @@ void writeRefreshAndPeriodLinks(String graphName, String part) throws IOExceptio
+ myPeriod.getLinkLabel() + "' /> ");
writeln(myPeriod.getLinkLabel() + "</a>&nbsp;");
}
new HtmlForms(getWriter()).writeCustomPeriodLink(range, graphName, part);
final HtmlForms htmlForms = new HtmlForms(getWriter());
final Map<String, Date> datesByWebappVersions = collector.getDatesByWebappVersions();
htmlForms.writeCustomPeriodLinks(datesByWebappVersions, range, graphName, part);

writeln(END_DIV);
}
Expand Down
Expand Up @@ -77,6 +77,7 @@ class JavaInformations implements Serializable { // NOPMD
private final String serverInfo;
private final String contextPath;
private final String contextDisplayName;
private final String webappVersion;
private final Date startDate;
private final String jvmArguments;
private final long freeDiskSpaceInTemp;
Expand Down Expand Up @@ -157,10 +158,12 @@ public int compare(JobInformations job1, JobInformations job2) {
serverInfo = null;
contextPath = null;
contextDisplayName = null;
webappVersion = null;
} else {
serverInfo = servletContext.getServerInfo();
contextPath = Parameters.getContextPath(servletContext);
contextDisplayName = servletContext.getServletContextName();
webappVersion = MavenArtifact.getWebappVersion();
}
startDate = START_DATE;
jvmArguments = buildJvmArguments();
Expand Down Expand Up @@ -590,6 +593,10 @@ String getContextDisplayName() {
return contextDisplayName;
}

String getWebappVersion() {
return webappVersion;
}

Date getStartDate() {
return startDate;
}
Expand Down

0 comments on commit d61e65f

Please sign in to comment.