forked from I2P_Developers/i2p.i2p
- Persistent option on GUI
- Fix HTML errors - Refresh improvements - Fix Rate.equals() bug - More cleanups
This commit is contained in:
@ -17,6 +17,7 @@ public class GraphHelper extends FormHandler {
|
||||
private int _width;
|
||||
private int _height;
|
||||
private int _refreshDelaySeconds;
|
||||
private boolean _persistent;
|
||||
|
||||
private static final String PROP_X = "routerconsole.graphX";
|
||||
private static final String PROP_Y = "routerconsole.graphY";
|
||||
@ -39,7 +40,19 @@ public class GraphHelper extends FormHandler {
|
||||
_height = _context.getProperty(PROP_Y, DEFAULT_Y);
|
||||
_periodCount = _context.getProperty(PROP_PERIODS, DEFAULT_PERIODS);
|
||||
_refreshDelaySeconds = _context.getProperty(PROP_REFRESH, DEFAULT_REFRESH);
|
||||
_showEvents = Boolean.valueOf(_context.getProperty(PROP_EVENTS)).booleanValue();
|
||||
_showEvents = _context.getBooleanProperty(PROP_EVENTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be output in the jsp since <meta> must be in the <head>
|
||||
* @since 0.8.6
|
||||
*/
|
||||
public String getRefreshMeta() {
|
||||
if (_refreshDelaySeconds <= 8 ||
|
||||
ConfigRestartBean.getRestartTimeRemaining() < (1000 * (_refreshDelaySeconds + 30)))
|
||||
return "";
|
||||
// shorten the refresh by 3 seconds so we beat the iframe
|
||||
return "<meta http-equiv=\"refresh\" content=\"" + (_refreshDelaySeconds - 3) + "\">";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,13 +64,17 @@ public class GraphHelper extends FormHandler {
|
||||
public void setPeriodCount(String str) {
|
||||
try { _periodCount = Integer.parseInt(str); } catch (NumberFormatException nfe) {}
|
||||
}
|
||||
|
||||
public void setShowEvents(boolean b) { _showEvents = b; }
|
||||
|
||||
public void setHeight(String str) {
|
||||
try { _height = Math.min(Integer.parseInt(str), MAX_Y); } catch (NumberFormatException nfe) {}
|
||||
}
|
||||
|
||||
public void setWidth(String str) {
|
||||
try { _width = Math.min(Integer.parseInt(str), MAX_X); } catch (NumberFormatException nfe) {}
|
||||
}
|
||||
|
||||
public void setRefreshDelay(String str) {
|
||||
try {
|
||||
int rds = Integer.parseInt(str);
|
||||
@ -68,6 +85,9 @@ public class GraphHelper extends FormHandler {
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
|
||||
/** @since 0.8.6 */
|
||||
public void setPersistent(String foo) { _persistent = true; }
|
||||
|
||||
public String getImages() {
|
||||
try {
|
||||
List listeners = StatSummarizer.instance().getListeners();
|
||||
@ -123,13 +143,9 @@ public class GraphHelper extends FormHandler {
|
||||
+ "\" alt=\"" + title
|
||||
+ "\" title=\"" + title + "\"></a>\n");
|
||||
}
|
||||
// FIXME <meta> not allowed inside <div>, move to the .jsp
|
||||
if (_refreshDelaySeconds > 0)
|
||||
// shorten the refresh by 3 seconds so we beat the iframe
|
||||
_out.write("<meta http-equiv=\"refresh\" content=\"" + (_refreshDelaySeconds - 3) + "\">\n");
|
||||
|
||||
// FIXME jrobin doesn't support setting the timezone, will have to mod TimeAxis.java
|
||||
_out.write("<p<i>" + _("All times are UTC.") + "</i></p>\n");
|
||||
_out.write("<p><i>" + _("All times are UTC.") + "</i></p>\n");
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
@ -148,11 +164,11 @@ public class GraphHelper extends FormHandler {
|
||||
_out.write("<form action=\"graphs\" method=\"POST\">\n" +
|
||||
"<input type=\"hidden\" name=\"action\" value=\"foo\">\n" +
|
||||
"<input type=\"hidden\" name=\"nonce\" value=\"" + nonce + "\" >\n");
|
||||
_out.write(_("Periods") + ": <input size=\"3\" type=\"text\" name=\"periodCount\" value=\"" + _periodCount + "\"><br>\n");
|
||||
_out.write(_("Periods") + ": <input size=\"5\" style=\"text-align: right;\" type=\"text\" name=\"periodCount\" value=\"" + _periodCount + "\"><br>\n");
|
||||
_out.write(_("Plot averages") + ": <input type=\"radio\" class=\"optbox\" name=\"showEvents\" value=\"false\" " + (_showEvents ? "" : "checked=\"true\" ") + "> ");
|
||||
_out.write(_("or")+ " " +_("plot events") + ": <input type=\"radio\" class=\"optbox\" name=\"showEvents\" value=\"true\" "+ (_showEvents ? "checked=\"true\" " : "") + "><br>\n");
|
||||
_out.write(_("Image sizes") + ": " + _("width") + ": <input size=\"4\" type=\"text\" name=\"width\" value=\"" + _width
|
||||
+ "\"> " + _("pixels") + ", " + _("height") + ": <input size=\"4\" type=\"text\" name=\"height\" value=\"" + _height
|
||||
_out.write(_("Image sizes") + ": " + _("width") + ": <input size=\"4\" style=\"text-align: right;\" type=\"text\" name=\"width\" value=\"" + _width
|
||||
+ "\"> " + _("pixels") + ", " + _("height") + ": <input size=\"4\" style=\"text-align: right;\" type=\"text\" name=\"height\" value=\"" + _height
|
||||
+ "\"> " + _("pixels") + "<br>\n");
|
||||
_out.write(_("Refresh delay") + ": <select name=\"refreshDelay\">");
|
||||
for (int i = 0; i < times.length; i++) {
|
||||
@ -169,7 +185,13 @@ public class GraphHelper extends FormHandler {
|
||||
_out.write("</option>\n");
|
||||
}
|
||||
_out.write("</select><br>\n" +
|
||||
"<hr><div class=\"formaction\"><input type=\"submit\" value=\"" + _("Redraw") + "\"></div></form>");
|
||||
_("Store graph data on disk?") +
|
||||
" <input type=\"checkbox\" class=\"optbox\" value=\"true\" name=\"persistent\"");
|
||||
boolean persistent = _context.getBooleanPropertyDefaultTrue(SummaryListener.PROP_PERSISTENT);
|
||||
if (persistent)
|
||||
_out.write(" checked=\"true\"");
|
||||
_out.write(">" +
|
||||
"<hr><div class=\"formaction\"><input type=\"submit\" value=\"" + _("Save settings and redraw graphs") + "\"></div></form>");
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
@ -194,26 +216,27 @@ public class GraphHelper extends FormHandler {
|
||||
_height != _context.getProperty(PROP_Y, DEFAULT_Y) ||
|
||||
_periodCount != _context.getProperty(PROP_PERIODS, DEFAULT_PERIODS) ||
|
||||
_refreshDelaySeconds != _context.getProperty(PROP_REFRESH, DEFAULT_REFRESH) ||
|
||||
_showEvents != Boolean.valueOf(_context.getProperty(PROP_EVENTS)).booleanValue()) {
|
||||
_showEvents != _context.getBooleanProperty(PROP_EVENTS) ||
|
||||
_persistent != _context.getBooleanPropertyDefaultTrue(SummaryListener.PROP_PERSISTENT)) {
|
||||
_context.router().setConfigSetting(PROP_X, "" + _width);
|
||||
_context.router().setConfigSetting(PROP_Y, "" + _height);
|
||||
_context.router().setConfigSetting(PROP_PERIODS, "" + _periodCount);
|
||||
_context.router().setConfigSetting(PROP_REFRESH, "" + _refreshDelaySeconds);
|
||||
_context.router().setConfigSetting(PROP_EVENTS, "" + _showEvents);
|
||||
_context.router().setConfigSetting(SummaryListener.PROP_PERSISTENT, "" + _persistent);
|
||||
_context.router().saveConfig();
|
||||
addFormNotice(_("Graph settings saved"));
|
||||
}
|
||||
}
|
||||
|
||||
/** inner class, don't bother reindenting */
|
||||
private static class AlphaComparator implements Comparator {
|
||||
public int compare(Object lhs, Object rhs) {
|
||||
SummaryListener l = (SummaryListener)lhs;
|
||||
SummaryListener r = (SummaryListener)rhs;
|
||||
String lName = l.getRate().getRateStat().getName() + "." + l.getRate().getPeriod();
|
||||
String rName = r.getRate().getRateStat().getName() + "." + r.getRate().getPeriod();
|
||||
return lName.compareTo(rName);
|
||||
private static class AlphaComparator implements Comparator<SummaryListener> {
|
||||
public int compare(SummaryListener l, SummaryListener r) {
|
||||
String lName = l.getRate().getRateStat().getName();
|
||||
String rName = r.getRate().getRateStat().getName();
|
||||
int rv = lName.compareTo(rName);
|
||||
if (rv != 0)
|
||||
return rv;
|
||||
return (int) (l.getRate().getPeriod() - r.getRate().getPeriod());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package net.i2p.router.web;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
@ -18,6 +19,7 @@ import javax.imageio.stream.MemoryCacheImageOutputStream;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.stat.Rate;
|
||||
import net.i2p.stat.RateStat;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import org.jrobin.core.RrdException;
|
||||
@ -60,6 +62,9 @@ public class StatSummarizer implements Runnable {
|
||||
public static StatSummarizer instance() { return _instance; }
|
||||
|
||||
public void run() {
|
||||
boolean isPersistent = _context.getBooleanPropertyDefaultTrue(SummaryListener.PROP_PERSISTENT);
|
||||
if (!isPersistent)
|
||||
deleteOldRRDs();
|
||||
_thread = Thread.currentThread();
|
||||
String specs = "";
|
||||
while (_isRunning && _context.router().isAlive()) {
|
||||
@ -126,10 +131,10 @@ public class StatSummarizer implements Runnable {
|
||||
}
|
||||
|
||||
private void removeDb(Rate r) {
|
||||
for (int i = 0; i < _listeners.size(); i++) {
|
||||
SummaryListener lsnr = _listeners.get(i);
|
||||
for (SummaryListener lsnr : _listeners) {
|
||||
if (lsnr.getRate().equals(r)) {
|
||||
_listeners.remove(i);
|
||||
// no iter.remove() in COWAL
|
||||
_listeners.remove(lsnr);
|
||||
lsnr.stopListening();
|
||||
return;
|
||||
}
|
||||
@ -178,8 +183,7 @@ public class StatSummarizer implements Runnable {
|
||||
height = GraphHelper.MAX_Y;
|
||||
else if (height <= 0)
|
||||
height = GraphHelper.DEFAULT_Y;
|
||||
for (int i = 0; i < _listeners.size(); i++) {
|
||||
SummaryListener lsnr = _listeners.get(i);
|
||||
for (SummaryListener lsnr : _listeners) {
|
||||
if (lsnr.getRate().equals(rate)) {
|
||||
lsnr.renderPng(out, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, showCredit);
|
||||
return true;
|
||||
@ -206,8 +210,7 @@ public class StatSummarizer implements Runnable {
|
||||
}
|
||||
|
||||
private boolean locked_getXML(Rate rate, OutputStream out) throws IOException {
|
||||
for (int i = 0; i < _listeners.size(); i++) {
|
||||
SummaryListener lsnr = _listeners.get(i);
|
||||
for (SummaryListener lsnr : _listeners) {
|
||||
if (lsnr.getRate().equals(rate)) {
|
||||
lsnr.getData().exportXml(out);
|
||||
out.write(("<!-- Rate: " + lsnr.getRate().getRateStat().getName() + " for period " + lsnr.getRate().getPeriod() + " -->\n").getBytes());
|
||||
@ -274,7 +277,6 @@ public class StatSummarizer implements Runnable {
|
||||
def.setTimeSpan(start/1000, end/1000);
|
||||
def.setMinValue(0d);
|
||||
def.setBase(1024);
|
||||
// Note to translators: all runtime zh translation disabled in this file, no font available in RRD
|
||||
String title = _("Bandwidth usage");
|
||||
if (!hideTitle)
|
||||
def.setTitle(title);
|
||||
@ -365,6 +367,15 @@ public class StatSummarizer implements Runnable {
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the old rrd dir if we are no longer persistent
|
||||
* @since 0.8.6
|
||||
*/
|
||||
private void deleteOldRRDs() {
|
||||
File rrdDir = new File(_context.getRouterDir(), SummaryListener.RRD_DIR);
|
||||
FileUtil.rmdir(rrdDir, false);
|
||||
}
|
||||
|
||||
/** translate a string */
|
||||
private String _(String s) {
|
||||
// the RRD font doesn't have zh chars, at least on my system
|
||||
|
@ -32,9 +32,9 @@ import org.jrobin.graph.RrdGraphDefTemplate;
|
||||
* @since 0.6.1.13
|
||||
*/
|
||||
class SummaryListener implements RateSummaryListener {
|
||||
private static final String PROP_PERSISTENT = "routerconsole.graphPersistent";
|
||||
static final String PROP_PERSISTENT = "routerconsole.graphPersistent";
|
||||
/** note that .jrb files are NOT compatible with .rrd files */
|
||||
private static final String RRD_DIR = "rrd";
|
||||
static final String RRD_DIR = "rrd";
|
||||
private static final String RRD_PREFIX = "rrd-";
|
||||
private static final String RRD_SUFFIX = ".jrb";
|
||||
static final String CF = "AVERAGE";
|
||||
@ -62,7 +62,7 @@ class SummaryListener implements RateSummaryListener {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
_rate = r;
|
||||
_log = _context.logManager().getLog(SummaryListener.class);
|
||||
_isPersistent = _context.getBooleanProperty(PROP_PERSISTENT);
|
||||
_isPersistent = _context.getBooleanPropertyDefaultTrue(PROP_PERSISTENT);
|
||||
}
|
||||
|
||||
public void add(double totalValue, long eventCount, double totalEventTime, long period) {
|
||||
|
@ -101,12 +101,11 @@ class SummaryRenderer {
|
||||
String title;
|
||||
String p;
|
||||
// we want the formatting and translation of formatDuration2(), except not zh, and not the
|
||||
if ("zh".equals(Messages.getLanguage(_context)))
|
||||
p = DataHelper.formatDuration(_listener.getRate().getPeriod());
|
||||
else
|
||||
//if ("zh".equals(Messages.getLanguage(_context)))
|
||||
// p = DataHelper.formatDuration(_listener.getRate().getPeriod());
|
||||
//else
|
||||
p = DataHelper.formatDuration2(_listener.getRate().getPeriod()).replace(" ", " ");
|
||||
if (showEvents)
|
||||
// Note to translators: all runtime zh translation disabled in this file, no font available in RRD
|
||||
title = name + ' ' + _("events in {0}", p);
|
||||
else
|
||||
title = name + ' ' + _("averaged for {0}", p);
|
||||
@ -133,7 +132,10 @@ class SummaryRenderer {
|
||||
if (started > start && started < end)
|
||||
def.vrule(started / 1000, Color.BLACK, _("Restart"), 4.0f);
|
||||
def.datasource(plotName, path, plotName, SummaryListener.CF, _listener.getBackendName());
|
||||
if (descr.length() > 0)
|
||||
def.area(plotName, Color.BLUE, descr + "\\r");
|
||||
else
|
||||
def.area(plotName, Color.BLUE);
|
||||
if (!hideLegend) {
|
||||
def.gprint(plotName, SummaryListener.CF, _("avg") + ": %.2f %s");
|
||||
def.gprint(plotName, "MAX", ' ' + _("max") + ": %.2f %S");
|
||||
|
@ -5,19 +5,26 @@
|
||||
<html><head>
|
||||
<%@include file="css.jsi" %>
|
||||
<%=intl.title("graphs")%>
|
||||
</head><body>
|
||||
|
||||
<%@include file="summary.jsi" %>
|
||||
<h1><%=intl._("I2P Performance Graphs")%></h1>
|
||||
<div class="main" id="main">
|
||||
<div class="graphspanel">
|
||||
<div class="widepanel">
|
||||
<jsp:useBean class="net.i2p.router.web.GraphHelper" id="graphHelper" scope="request" />
|
||||
<% graphHelper.storeMethod(request.getMethod()); %>
|
||||
<jsp:setProperty name="graphHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
<% /* GraphHelper sets the defaults in setContextId, so setting the properties must be after the context */ %>
|
||||
<jsp:setProperty name="graphHelper" property="*" />
|
||||
<% graphHelper.storeWriter(out); %>
|
||||
<%
|
||||
graphHelper.storeWriter(out);
|
||||
graphHelper.storeMethod(request.getMethod());
|
||||
// meta must be inside the head
|
||||
boolean allowRefresh = intl.allowIFrame(request.getHeader("User-Agent"));
|
||||
if (allowRefresh) {
|
||||
out.print(graphHelper.getRefreshMeta());
|
||||
}
|
||||
%>
|
||||
</head><body>
|
||||
<%@include file="summary.jsi" %>
|
||||
<h1><%=intl._("I2P Performance Graphs")%></h1>
|
||||
<div class="main" id="main">
|
||||
<div class="graphspanel">
|
||||
<div class="widepanel">
|
||||
<jsp:getProperty name="graphHelper" property="allMessages" />
|
||||
<jsp:getProperty name="graphHelper" property="images" />
|
||||
<jsp:getProperty name="graphHelper" property="form" />
|
||||
|
@ -3,6 +3,7 @@ package net.i2p.stat;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@ -471,48 +472,28 @@ public class Rate {
|
||||
coalesce();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used in StatSummarizer and SummaryListener.
|
||||
* We base it on the stat we are tracking, not the stored data.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ((obj == null) || !(obj instanceof Rate)) return false;
|
||||
if (obj == this) return true;
|
||||
Rate r = (Rate) obj;
|
||||
return _period == r.getPeriod() && _creationDate == r.getCreationDate() &&
|
||||
//_lastCoalesceDate == r.getLastCoalesceDate() &&
|
||||
_currentTotalValue == r.getCurrentTotalValue() && _currentEventCount == r.getCurrentEventCount()
|
||||
&& _currentTotalEventTime == r.getCurrentTotalEventTime() && _lastTotalValue == r.getLastTotalValue()
|
||||
&& _lastEventCount == r.getLastEventCount() && _lastTotalEventTime == r.getLastTotalEventTime()
|
||||
&& _extremeTotalValue == r.getExtremeTotalValue() && _extremeEventCount == r.getExtremeEventCount()
|
||||
&& _extremeTotalEventTime == r.getExtremeTotalEventTime()
|
||||
&& _lifetimeTotalValue == r.getLifetimeTotalValue() && _lifetimeEventCount == r.getLifetimeEventCount()
|
||||
&& _lifetimeTotalEventTime == r.getLifetimeTotalEventTime();
|
||||
// do this the easy way to avoid NPEs.
|
||||
// Alternative: compare name and group name (very carefully to avoid NPEs)
|
||||
_stat == r._stat;
|
||||
}
|
||||
|
||||
/**
|
||||
* It doesn't appear that Rates are ever stored in a Set or Map
|
||||
* (RateStat stores in an array) so let's make this easy.
|
||||
* We can always make something faster if it's actually used.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
/*****
|
||||
int hash = 5;
|
||||
hash = 67 * hash + (int)(Double.doubleToLongBits(this._currentTotalValue) ^ (Double.doubleToLongBits(this._currentTotalValue) >>> 32));
|
||||
hash = 67 * hash + (int)(this._currentEventCount ^ (this._currentEventCount >>> 32));
|
||||
hash = 67 * hash + (int)(this._currentTotalEventTime ^ (this._currentTotalEventTime >>> 32));
|
||||
hash = 67 * hash + (int)(Double.doubleToLongBits(this._lastTotalValue) ^ (Double.doubleToLongBits(this._lastTotalValue) >>> 32));
|
||||
hash = 67 * hash + (int)(this._lastEventCount ^ (this._lastEventCount >>> 32));
|
||||
hash = 67 * hash + (int)(this._lastTotalEventTime ^ (this._lastTotalEventTime >>> 32));
|
||||
hash = 67 * hash + (int)(Double.doubleToLongBits(this._extremeTotalValue) ^ (Double.doubleToLongBits(this._extremeTotalValue) >>> 32));
|
||||
hash = 67 * hash + (int)(this._extremeEventCount ^ (this._extremeEventCount >>> 32));
|
||||
hash = 67 * hash + (int)(this._extremeTotalEventTime ^ (this._extremeTotalEventTime >>> 32));
|
||||
hash = 67 * hash + (int)(Double.doubleToLongBits(this._lifetimeTotalValue) ^ (Double.doubleToLongBits(this._lifetimeTotalValue) >>> 32));
|
||||
hash = 67 * hash + (int)(this._lifetimeEventCount ^ (this._lifetimeEventCount >>> 32));
|
||||
hash = 67 * hash + (int)(this._lifetimeTotalEventTime ^ (this._lifetimeTotalEventTime >>> 32));
|
||||
hash = 67 * hash + (int)(this._creationDate ^ (this._creationDate >>> 32));
|
||||
hash = 67 * hash + (int)(this._period ^ (this._period >>> 32));
|
||||
return hash;
|
||||
******/
|
||||
return toString().hashCode();
|
||||
return DataHelper.hashCode(_stat) ^ ((int)_period) ^ ((int) _creationDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Reference in New Issue
Block a user