FELIX-2498 Add support to limit memory dumps written by setting a minimum dump interval
FELIX-2498 Set default threshold for automatic memory dumps to zero
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@981193 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConfigurator.java b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConfigurator.java
index 7fbe40a..42bdc1c 100644
--- a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConfigurator.java
+++ b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConfigurator.java
@@ -67,7 +67,7 @@
}
catch (NumberFormatException nfe)
{
- throw failure(thresholdValue);
+ throw thresholdFailure(thresholdValue);
}
}
@@ -77,7 +77,7 @@
}
catch (IllegalArgumentException iae)
{
- throw failure(iae.getMessage());
+ throw thresholdFailure(iae.getMessage());
}
}
else
@@ -85,6 +85,41 @@
support.setThreshold(-1);
}
+ final Object intervalValue = properties.get(MemoryUsageConstants.PROP_DUMP_INTERVAL);
+ if (intervalValue != null)
+ {
+ final int interval;
+ if (intervalValue instanceof Number)
+ {
+ interval = ((Number) intervalValue).intValue();
+ }
+ else
+ {
+ // try to convert
+ try
+ {
+ interval = Integer.parseInt(intervalValue.toString());
+ }
+ catch (NumberFormatException nfe)
+ {
+ throw intervalFailure(intervalValue);
+ }
+ }
+
+ try
+ {
+ support.setInterval(interval);
+ }
+ catch (IllegalArgumentException iae)
+ {
+ throw intervalFailure(iae.getMessage());
+ }
+ }
+ else
+ {
+ support.setInterval(-1);
+ }
+
final Object locationValue = properties.get(MemoryUsageConstants.PROP_DUMP_LOCATION);
if (locationValue instanceof String)
{
@@ -112,11 +147,12 @@
{
final ArrayList<AttributeDefinition> adList = new ArrayList<AttributeDefinition>();
+
adList.add(new AttributeDefinitionImpl(MemoryUsageConstants.PROP_DUMP_THRESHOLD, "Dump Threshold",
"Threshold at which to automatically create a memory dump as a percentage in the range "
- + MemoryUsageConstants.MIN_DUMP_THRESHOLD + " to " + MemoryUsageConstants.MAX_DUMP_THRESHOLD
- + " or zero to disable automatic dump creation.", AttributeDefinition.INTEGER, new String[]
- { String.valueOf(MemoryUsageConstants.DEFAULT_DUMP_THRESHOLD) }, 0, null, null)
+ + MemoryUsageConstants.MIN_DUMP_THRESHOLD + " to " + MemoryUsageConstants.MAX_DUMP_THRESHOLD
+ + " or zero to disable automatic dump creation.", AttributeDefinition.INTEGER, new String[]
+ { String.valueOf(MemoryUsageConstants.DEFAULT_DUMP_THRESHOLD) }, 0, null, null)
{
@Override
public String validate(String value)
@@ -126,17 +162,49 @@
int threshold = Integer.parseInt(value);
if (!MemoryUsageConstants.isThresholdValid(threshold))
{
- return "Threshold must in the range " + MemoryUsageConstants.MIN_DUMP_THRESHOLD + " to "
- + MemoryUsageConstants.MAX_DUMP_THRESHOLD + " or zero";
+ return "Dump Threshold must in the range " + MemoryUsageConstants.MIN_DUMP_THRESHOLD
+ + " to " + MemoryUsageConstants.MAX_DUMP_THRESHOLD + " or zero";
}
return ""; // everything ok
}
catch (NumberFormatException nfe)
{
- return "Threshhold must be numeric";
+ return "Dump Threshhold must be numeric";
}
}
});
+
+ adList.add(new AttributeDefinitionImpl(MemoryUsageConstants.PROP_DUMP_INTERVAL, "Dump Interval",
+ "The minimum interval between two consecutive memory dumps being taken in seconds. "
+ + "This property allows the limitation of the number of memory dumps being taken. "
+ + "The default value for the interval is 6 hours. This means that a memory threshold "
+ + "event is ignored unless the last memory dump has been taken at least 6 hours earlier. "
+ + "This property allows limiting the number of memory dumps in case memory consumption is "
+ + "oscillating around the threshold point. The property must be an integer value or be "
+ + "parseable to an integer value. This should be a positive value or zero to force each "
+ + "memory threshold event to cause a memory dump (discouraged).", AttributeDefinition.INTEGER,
+ new String[]
+ { String.valueOf(MemoryUsageConstants.DEFAULT_DUMP_INTERVAL) }, 0, null, null)
+ {
+ @Override
+ public String validate(String value)
+ {
+ try
+ {
+ int interval = Integer.parseInt(value);
+ if (interval < 0)
+ {
+ return "Dump Interval must be zero or a positive number";
+ }
+ return ""; // everything ok
+ }
+ catch (NumberFormatException nfe)
+ {
+ return "Dump Interval must be numeric";
+ }
+ }
+ });
+
adList.add(new AttributeDefinitionImpl(MemoryUsageConstants.PROP_DUMP_LOCATION, "Dumpe Location",
"The filesystem location where heap dumps are stored. If this is null or empty (the default) the dumps are stored in "
+ support.getDefaultDumpLocation(), ""));
@@ -176,13 +244,19 @@
return ocd;
}
- private ConfigurationException failure(final Object invalidValue)
+ private ConfigurationException thresholdFailure(final Object invalidValue)
{
return new ConfigurationException(MemoryUsageConstants.PROP_DUMP_THRESHOLD, "Invalid Dump Threshold value '"
+ invalidValue + "': Must be an integer number in the range " + MemoryUsageConstants.MIN_DUMP_THRESHOLD
+ " to " + MemoryUsageConstants.MAX_DUMP_THRESHOLD + " or zero to disable");
}
+ private ConfigurationException intervalFailure(final Object invalidValue)
+ {
+ return new ConfigurationException(MemoryUsageConstants.PROP_DUMP_INTERVAL, "Invalid Dump Interval value '"
+ + invalidValue + "': Must be a positive integer number or zero to disable");
+ }
+
private static class AttributeDefinitionImpl implements AttributeDefinition
{
diff --git a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConstants.java b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConstants.java
index a89ff98..87964e1 100644
--- a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConstants.java
+++ b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConstants.java
@@ -64,20 +64,47 @@
static final String PROP_DUMP_THRESHOLD = "felix.memoryusage.dump.threshold";
/**
+ * The minimum interval between two consecutive memory dumps being taken
+ * in seconds. This property allows the limitation of the number of memory
+ * dumps being taken. The default value for the interval is 6 hours. This
+ * means that
+ * a memory threshold event is ignored unless the last memory dump has been
+ * taken
+ * at least 6 hours earlier.
+ * <p>
+ * This property allows limiting the number of memory dumps in case memory
+ * consumption is oscillating around the threshold point.
+ * <p>
+ * The property must be an integer value or be parseable to an integer
+ * value. This should be a positive value or zero to force each memory
+ * threshold event to cause a memory dump (discouraged). If the value is
+ * negative or not parseable to an int, the default value of
+ * {@link #DEFAULT_DUMP_INTERVAL 6 hours} applies.
+ */
+ static final String PROP_DUMP_INTERVAL = "felix.memoryusage.dump.interval";
+
+ /**
* The default automatic heap dump threshold if none has been configured
* (or no configuration has yet been provided).
*/
- static final int DEFAULT_DUMP_THRESHOLD = 95;
+ static final int DEFAULT_DUMP_THRESHOLD = 0;
+
/**
* The maximum allowed automatic heap dump threshold.
*/
static final int MAX_DUMP_THRESHOLD = 99;
+
/**
* The minimum allowed automatic heap dump threshold.
*/
static final int MIN_DUMP_THRESHOLD = 50;
/**
+ * The default interval betwen consecutive dumps (6 hours).
+ */
+ static final long DEFAULT_DUMP_INTERVAL = 6 * 3600 * 1000;
+
+ /**
* Returns <code>true</code> if the given <code>threshold</code>value is
* valid; that is if the vaue is either zero or in the range [
* {@link #MIN_DUMP_THRESHOLD}..{@link #MAX_DUMP_THRESHOLD}].
diff --git a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsagePanel.java b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsagePanel.java
index 8af03ca..4899b4b 100644
--- a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsagePanel.java
+++ b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsagePanel.java
@@ -40,7 +40,6 @@
import org.apache.felix.webconsole.ConfigurationPrinter;
import org.apache.felix.webconsole.DefaultVariableResolver;
import org.apache.felix.webconsole.WebConsoleUtil;
-import org.osgi.framework.BundleContext;
import org.osgi.service.log.LogService;
@SuppressWarnings("serial")
@@ -113,6 +112,7 @@
resolver.put("__files__", filesBuf.toString());
resolver.put("__status__", statusBuf.toString());
resolver.put("__threshold__", String.valueOf(support.getThreshold()));
+ resolver.put("__interval__", String.valueOf(support.getInterval()));
resolver.put("__overall__", jph.getString());
resolver.put("__pools__", support.getMemoryPoolsJson());
@@ -214,6 +214,19 @@
}
resp.sendRedirect(req.getRequestURI());
}
+ else if ("interval".equals(command))
+ {
+ try
+ {
+ int interval = Integer.parseInt(req.getParameter("interval"));
+ support.setInterval(interval);
+ }
+ catch (Exception e)
+ {
+ // ignore
+ }
+ resp.sendRedirect(req.getRequestURI());
+ }
else
{
super.doPost(req, resp);
diff --git a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageSupport.java b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageSupport.java
index 5e65893..484c874 100644
--- a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageSupport.java
+++ b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageSupport.java
@@ -64,12 +64,22 @@
// the default threshold value
private final int defaultThreshold;
+ // the minimum number of milliseconds between two consecutive memory
+ // dumps written. this setting allows limitting the generation of memory
+ // dumps if memory consumption is oscillating around the memory
+ // threshold value
+ private long minDumpInterval;
+
// the configured dump location
private File dumpLocation;
// the actual threshold (configured or dynamically set in the console UI)
private int threshold;
+ // the system time of the last memory snapshot written; initialized so as
+ // at least write one dump
+ private long nextDumpTime = -1;
+
// log service
private ServiceReference logServiceReference;
private Object logService;
@@ -151,6 +161,29 @@
}
this.defaultThreshold = defaultThreshold;
+
+ // set the initial automatic dump threshold
+ int interval;
+ String propInterval = context.getProperty(MemoryUsageConstants.PROP_DUMP_INTERVAL);
+ if (propInterval != null)
+ {
+ try
+ {
+ interval = Integer.parseInt(propInterval);
+ }
+ catch (Exception e)
+ {
+ // NumberFormatException - if propTreshold cannot be parsed to
+ // int
+ // IllegalArgumentException - if threshold is invalid
+ interval = -1;
+ }
+ }
+ else
+ {
+ interval = -1;
+ }
+ setInterval(interval);
}
void dispose()
@@ -233,10 +266,30 @@
return threshold;
}
+ final void setInterval(long interval)
+ {
+ if (interval < 0)
+ {
+ interval = MemoryUsageConstants.DEFAULT_DUMP_INTERVAL;
+ }
+ else
+ {
+ interval = 1000L * interval;
+ }
+ this.minDumpInterval = interval;
+ log(LogService.LOG_INFO, "Setting Automatic Memory Dump Interval to %d seconds", getInterval());
+ }
+
+ final long getInterval()
+ {
+ return minDumpInterval / 1000L;
+ }
+
final void printMemory(final PrintHelper pw)
{
pw.title("Overall Memory Use", 0);
pw.keyVal("Heap Dump Threshold", getThreshold() + "%");
+ pw.keyVal("Heap Dump Interval", getInterval() + " seconds");
printOverallMemory(pw);
pw.title("Memory Pools", 0);
@@ -502,16 +555,25 @@
String notifType = notification.getType();
if (notifType.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED))
{
- log(LogService.LOG_WARNING, "Received Memory Threshold Exceed Notification, dumping Heap");
- try
+ if (System.currentTimeMillis() >= nextDumpTime)
{
- File file = dumpHeap(null, true);
- log(LogService.LOG_WARNING, "Heap dumped to " + file);
+ log(LogService.LOG_WARNING, "Received Memory Threshold Exceeded Notification, dumping Heap");
+ try
+ {
+ File file = dumpHeap(null, true);
+ log(LogService.LOG_WARNING, "Heap dumped to " + file);
+ nextDumpTime = System.currentTimeMillis() + minDumpInterval;
+ }
+ catch (NoSuchElementException e)
+ {
+ log(LogService.LOG_ERROR,
+ "Failed dumping the heap, JVM does not provide known mechanism to create a Heap Dump");
+ }
}
- catch (NoSuchElementException e)
+ else
{
- log(LogService.LOG_ERROR,
- "Failed dumping the heap, JVM does not provide known mechanism to create a Heap Dump");
+ log(LogService.LOG_WARNING,
+ "Ignoring Memory Threshold Exceeded Notification, minimum dump interval since last dump has not passed yet");
}
}
}
diff --git a/webconsole-plugins/memoryusage/src/main/resources/OSGI-INF/l10n/bundle.properties b/webconsole-plugins/memoryusage/src/main/resources/OSGI-INF/l10n/bundle.properties
index fdf0132..f10faba 100644
--- a/webconsole-plugins/memoryusage/src/main/resources/OSGI-INF/l10n/bundle.properties
+++ b/webconsole-plugins/memoryusage/src/main/resources/OSGI-INF/l10n/bundle.properties
@@ -36,6 +36,8 @@
dump.overview = Memory Usage Overview
dump.threshold = Automatic Heap Dump Threshold (%)
dump.threshold.set = Set Threshold
+dump.interval = Automatic Heap Dump Interval (s)
+dump.interval.set = Set Interval
dump.pools.name = Name
dump.pools.score = Usage Score
diff --git a/webconsole-plugins/memoryusage/src/main/resources/OSGI-INF/l10n/bundle_de.properties b/webconsole-plugins/memoryusage/src/main/resources/OSGI-INF/l10n/bundle_de.properties
index 76c4c56..7f844d6 100644
--- a/webconsole-plugins/memoryusage/src/main/resources/OSGI-INF/l10n/bundle_de.properties
+++ b/webconsole-plugins/memoryusage/src/main/resources/OSGI-INF/l10n/bundle_de.properties
@@ -36,6 +36,8 @@
dump.overview = Hauptspeicher Nutzung Übersicht
dump.threshold = Speicher Abbild Schwellwert (%)
dump.threshold.set = Schwellwert setzen
+dump.interval = Speicher Abbild Intervall (s)
+dump.interval.set = Intervall setzen
dump.pools.name = Name
dump.pools.score = Nutzung
diff --git a/webconsole-plugins/memoryusage/src/main/resources/templates/memoryusage.html b/webconsole-plugins/memoryusage/src/main/resources/templates/memoryusage.html
index 0ca537e..8a8c2fd 100644
--- a/webconsole-plugins/memoryusage/src/main/resources/templates/memoryusage.html
+++ b/webconsole-plugins/memoryusage/src/main/resources/templates/memoryusage.html
@@ -172,6 +172,16 @@
</form>
</td>
</tr>
+ <tr>
+ <td>${dump.interval}</td>
+ <td>
+ <form method="post" action="">
+ <input type="hidden" name="command" value="interval" />
+ <input type="text" name="interval" value="${__interval__}" />
+ <input type="submit" name="submit" value="${dump.interval.set}" />
+ </form>
+ </td>
+ </tr>
</tbody>
</table>