* Console: Add /graph support for bw.combined, consolidate

rendering code (ticket #890)
This commit is contained in:
zzz
2013-04-13 12:13:55 +00:00
parent 49cc6b5100
commit 21e47e61f0
7 changed files with 117 additions and 116 deletions

View File

@@ -126,6 +126,7 @@ public class GraphHelper extends FormHandler {
/** /**
* For single stat page * For single stat page
* @param "bw.combined" treated specially
* @since 0.9 * @since 0.9
*/ */
public void setStat(String stat) { public void setStat(String stat) {
@@ -151,10 +152,10 @@ public class GraphHelper extends FormHandler {
} }
if (hasTx && hasRx && !_showEvents) { if (hasTx && hasRx && !_showEvents) {
_out.write("<a href=\"viewstat?stat=bw.combined" _out.write("<a href=\"graph?stat=bw.combined"
+ "&amp;periodCount=" + (3 * _periodCount ) + "&amp;c=" + (3 * _periodCount )
+ "&amp;width=" + (3 * _width) + "&amp;w=" + (3 * _width)
+ "&amp;height=" + (3 * _height) + "&amp;h=" + (3 * _height)
+ "\">"); + "\">");
String title = _("Combined bandwidth graph"); String title = _("Combined bandwidth graph");
_out.write("<img class=\"statimage\"" _out.write("<img class=\"statimage\""
@@ -200,7 +201,9 @@ public class GraphHelper extends FormHandler {
} }
/** /**
* For single stat page * For single stat page;
* stat = "bw.combined" treated specially
*
* @since 0.9 * @since 0.9
*/ */
public String getSingleStat() { public String getSingleStat() {
@@ -208,25 +211,36 @@ public class GraphHelper extends FormHandler {
if (StatSummarizer.isDisabled()) if (StatSummarizer.isDisabled())
return ""; return "";
if (_stat == null) { if (_stat == null) {
_out.write("No stat"); _out.write("No stat specified");
return ""; return "";
} }
List<Rate> rates = StatSummarizer.instance().parseSpecs(_stat); long period;
if (rates.size() != 1) { String name, displayName;
_out.write("Graphs not enabled for " + _stat); if (_stat.equals("bw.combined")) {
return ""; period = 60000;
name = _stat;
displayName = _("Bandwidth usage");
} else {
List<Rate> rates = StatSummarizer.instance().parseSpecs(_stat);
if (rates.size() != 1) {
_out.write("Graphs not enabled for " + _stat);
return "";
}
Rate r = rates.get(0);
period = r.getPeriod();
name = r.getRateStat().getName();
displayName = name;
} }
Rate r = rates.get(0);
_out.write("<h3>"); _out.write("<h3>");
_out.write(_("{0} for {1}", r.getRateStat().getName(), DataHelper.formatDuration2(_periodCount * r.getPeriod()))); _out.write(_("{0} for {1}", displayName, DataHelper.formatDuration2(_periodCount * period)));
if (_end > 0) if (_end > 0)
_out.write(' ' + _("ending {0} ago", DataHelper.formatDuration2(_end * r.getPeriod()))); _out.write(' ' + _("ending {0} ago", DataHelper.formatDuration2(_end * period)));
_out.write("</h3><img class=\"statimage\" border=\"0\"" _out.write("</h3><img class=\"statimage\" border=\"0\""
+ " src=\"viewstat.jsp?stat=" + " src=\"viewstat.jsp?stat="
+ r.getRateStat().getName() + name
+ "&amp;showEvents=" + _showEvents + "&amp;showEvents=" + _showEvents
+ "&amp;period=" + r.getPeriod() + "&amp;period=" + period
+ "&amp;periodCount=" + _periodCount + "&amp;periodCount=" + _periodCount
+ "&amp;end=" + _end + "&amp;end=" + _end
+ "&amp;width=" + _width + "&amp;width=" + _width
@@ -302,7 +316,8 @@ public class GraphHelper extends FormHandler {
_out.write("<br>"); _out.write("<br>");
_out.write(link(_stat, !_showEvents, _periodCount, _end, _width, _height)); _out.write(link(_stat, !_showEvents, _periodCount, _end, _width, _height));
_out.write(_showEvents ? _("Plot averages") : _("plot events")); if (!_stat.equals("bw.combined"))
_out.write(_showEvents ? _("Plot averages") : _("plot events"));
_out.write("</a>"); _out.write("</a>");
_out.write("</p><p><i>" + _("All times are UTC.") + "</i></p>\n"); _out.write("</p><p><i>" + _("All times are UTC.") + "</i></p>\n");

View File

@@ -245,7 +245,7 @@ public class StatSummarizer implements Runnable {
if (lsnr.getRate().equals(rate)) { if (lsnr.getRate().equals(rate)) {
lsnr.getData().exportXml(out); lsnr.getData().exportXml(out);
out.write(("<!-- Rate: " + lsnr.getRate().getRateStat().getName() + " for period " + lsnr.getRate().getPeriod() + " -->\n").getBytes()); out.write(("<!-- Rate: " + lsnr.getRate().getRateStat().getName() + " for period " + lsnr.getRate().getPeriod() + " -->\n").getBytes());
out.write(("<!-- Average data soure name: " + lsnr.getName() + " event count data source name: " + lsnr.getEventName() + " -->\n").getBytes()); out.write(("<!-- Average data source name: " + lsnr.getName() + " event count data source name: " + lsnr.getEventName() + " -->\n").getBytes());
return true; return true;
} }
} }
@@ -254,19 +254,21 @@ public class StatSummarizer implements Runnable {
/** /**
* This does the two-data bandwidth graph only. * This does the two-data bandwidth graph only.
* For all other graphs see SummaryRenderer * For all other graphs see renderPng() above.
* Synchronized to conserve memory. * Synchronized to conserve memory.
*
* @param end number of periods before now
* @return success * @return success
*/ */
public boolean renderRatePng(OutputStream out, int width, int height, boolean hideLegend, public boolean renderRatePng(OutputStream out, int width, int height, boolean hideLegend,
boolean hideGrid, boolean hideTitle, boolean showEvents, boolean hideGrid, boolean hideTitle, boolean showEvents,
int periodCount, boolean showCredit) throws IOException { int periodCount, int end, boolean showCredit) throws IOException {
try { try {
try { try {
_sem.acquire(); _sem.acquire();
} catch (InterruptedException ie) {} } catch (InterruptedException ie) {}
return locked_renderRatePng(out, width, height, hideLegend, hideGrid, hideTitle, showEvents, return locked_renderRatePng(out, width, height, hideLegend, hideGrid, hideTitle, showEvents,
periodCount, showCredit); periodCount, end, showCredit);
} finally { } finally {
_sem.release(); _sem.release();
} }
@@ -274,7 +276,7 @@ public class StatSummarizer implements Runnable {
private boolean locked_renderRatePng(OutputStream out, int width, int height, boolean hideLegend, private boolean locked_renderRatePng(OutputStream out, int width, int height, boolean hideLegend,
boolean hideGrid, boolean hideTitle, boolean showEvents, boolean hideGrid, boolean hideTitle, boolean showEvents,
int periodCount, boolean showCredit) throws IOException { int periodCount, int end, boolean showCredit) throws IOException {
// go to some trouble to see if we have the data for the combined bw graph // go to some trouble to see if we have the data for the combined bw graph
SummaryListener txLsnr = null; SummaryListener txLsnr = null;
@@ -289,7 +291,6 @@ public class StatSummarizer implements Runnable {
if (txLsnr == null || rxLsnr == null) if (txLsnr == null || rxLsnr == null)
throw new IOException("no rates for combined graph"); throw new IOException("no rates for combined graph");
long end = _context.clock().now() - 75*1000;
if (width > GraphHelper.MAX_X) if (width > GraphHelper.MAX_X)
width = GraphHelper.MAX_X; width = GraphHelper.MAX_X;
else if (width <= 0) else if (width <= 0)
@@ -298,86 +299,9 @@ public class StatSummarizer implements Runnable {
height = GraphHelper.MAX_Y; height = GraphHelper.MAX_Y;
else if (height <= 0) else if (height <= 0)
height = GraphHelper.DEFAULT_Y; height = GraphHelper.DEFAULT_Y;
if (periodCount <= 0 || periodCount > txLsnr.getRows()) txLsnr.renderPng(out, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount,
periodCount = txLsnr.getRows(); end, showCredit, rxLsnr, _("Bandwidth usage"));
long period = 60*1000; return true;
long start = end - period*periodCount;
//long begin = System.currentTimeMillis();
ImageOutputStream ios = null;
try {
RrdGraphDef def = new RrdGraphDef();
def.setTimeSpan(start/1000, end/1000);
def.setMinValue(0d);
def.setBase(1024);
String title = _("Bandwidth usage");
if (!hideTitle)
def.setTitle(title);
long started = _context.router().getWhenStarted();
if (started > start && started < end)
def.vrule(started / 1000, SummaryRenderer.RESTART_BAR_COLOR, null, 4.0f); // no room for legend
String sendName = SummaryListener.createName(_context, "bw.sendRate.60000");
String recvName = SummaryListener.createName(_context, "bw.recvRate.60000");
def.datasource(sendName, txLsnr.getData().getPath(), sendName, SummaryListener.CF, txLsnr.getBackendName());
def.datasource(recvName, rxLsnr.getData().getPath(), recvName, SummaryListener.CF, rxLsnr.getBackendName());
def.area(sendName, Color.BLUE, _("Outbound Bytes/sec"));
//def.line(sendName, Color.BLUE, "Outbound bytes/sec", 3);
def.line(recvName, Color.RED, _("Inbound Bytes/sec") + "\\r", 3);
//def.area(recvName, Color.RED, "Inbound bytes/sec@r");
if (!hideLegend) {
def.gprint(sendName, SummaryListener.CF, _("Out average") + ": %.2f %s" + _("Bps"));
def.gprint(sendName, "MAX", ' ' + _("max") + ": %.2f %S" + _("Bps") + "\\r");
def.gprint(recvName, SummaryListener.CF, _("In average") + ": %.2f %S" + _("Bps"));
def.gprint(recvName, "MAX", ' ' + _("max") + ": %.2f %S" + _("Bps") + "\\r");
// '07-Jul 21:09 UTC' with month name in the system locale
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM HH:mm");
def.comment(sdf.format(new Date(start)) + " -- " + sdf.format(new Date(end)) + " UTC\\r");
}
if (!showCredit)
def.setShowSignature(false);
if (hideLegend)
def.setNoLegend(true);
if (hideGrid) {
def.setDrawXGrid(false);
def.setDrawYGrid(false);
}
//System.out.println("rendering: path=" + path + " dsNames[0]=" + dsNames[0] + " dsNames[1]=" + dsNames[1] + " lsnr.getName=" + _listener.getName());
def.setAntiAliasing(false);
//System.out.println("Rendering: \n" + def.exportXmlTemplate());
//System.out.println("*****************\nData: \n" + _listener.getData().dump());
def.setWidth(width);
def.setHeight(height);
def.setImageFormat("PNG");
def.setLazy(true);
RrdGraph graph = new RrdGraph(def);
//System.out.println("Graph created");
int totalWidth = graph.getRrdGraphInfo().getWidth();
int totalHeight = graph.getRrdGraphInfo().getHeight();
BufferedImage img = new BufferedImage(totalWidth, totalHeight, BufferedImage.TYPE_USHORT_565_RGB);
Graphics gfx = img.getGraphics();
graph.render(gfx);
ios = new MemoryCacheImageOutputStream(out);
ImageIO.write(img, "png", ios);
//File t = File.createTempFile("jrobinData", ".xml");
//_listener.getData().dumpXml(new FileOutputStream(t));
//System.out.println("plotted: " + (data != null ? data.length : 0) + " bytes in " + timeToPlot
// ); // + ", data written to " + t.getAbsolutePath());
return true;
} catch (RrdException re) {
_log.error("Error rendering", re);
throw new IOException("Error plotting: " + re.getMessage());
} catch (IOException ioe) {
if (_log.shouldLog(Log.WARN))
_log.warn("Error rendering", ioe);
throw ioe;
} catch (OutOfMemoryError oom) {
_log.error("Error rendering", oom);
throw new IOException("Error plotting: " + oom.getMessage());
} finally {
// this does not close the underlying stream
if (ios != null) try {ios.close();} catch (IOException ioe) {}
}
} }
/** /**

View File

@@ -187,14 +187,31 @@ class SummaryListener implements RateSummaryListener {
} }
/** /**
* Single graph.
*
* @param end number of periods before now * @param end number of periods before now
*/ */
public void renderPng(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, public void renderPng(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid,
boolean hideTitle, boolean showEvents, int periodCount, boolean hideTitle, boolean showEvents, int periodCount,
int end, boolean showCredit) throws IOException { int end, boolean showCredit) throws IOException {
renderPng(out, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount,
end, showCredit, null, null);
}
/**
* Single or two-data-source graph.
*
* @param lsnr2 2nd data source to plot on same graph, or null. Not recommended for events.
* @param titleOverride If non-null, overrides the title
* @since 0.9.6
*/
public void renderPng(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid,
boolean hideTitle, boolean showEvents, int periodCount,
int end, boolean showCredit, SummaryListener lsnr2, String titleOverride) throws IOException {
if (_renderer == null || _db == null) if (_renderer == null || _db == null)
throw new IOException("No RRD, check logs for previous errors"); throw new IOException("No RRD, check logs for previous errors");
_renderer.render(out, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, end, showCredit); _renderer.render(out, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount,
end, showCredit, lsnr2, titleOverride);
} }
public void renderPng(OutputStream out) throws IOException { public void renderPng(OutputStream out) throws IOException {

View File

@@ -27,8 +27,7 @@ import org.jrobin.graph.RrdGraphDefTemplate;
/** /**
* Generate the RRD graph png images, * Generate the RRD graph png images,
* except for the combined rate graph, which is * including the combined rate graph.
* generated in StatSummarizer.
* *
* @since 0.6.1.13 * @since 0.6.1.13
*/ */
@@ -36,7 +35,7 @@ class SummaryRenderer {
private final Log _log; private final Log _log;
private final SummaryListener _listener; private final SummaryListener _listener;
private final I2PAppContext _context; private final I2PAppContext _context;
static final Color RESTART_BAR_COLOR = new Color(255, 144, 0, 224); private static final Color RESTART_BAR_COLOR = new Color(255, 144, 0, 224);
public SummaryRenderer(I2PAppContext ctx, SummaryListener lsnr) { public SummaryRenderer(I2PAppContext ctx, SummaryListener lsnr) {
_log = ctx.logManager().getLog(SummaryRenderer.class); _log = ctx.logManager().getLog(SummaryRenderer.class);
@@ -51,8 +50,11 @@ class SummaryRenderer {
* specify who can get it from where, etc. * specify who can get it from where, etc.
* *
* @deprecated unsed * @deprecated unsed
* @throws UnsupportedOperationException always
*/ */
public static synchronized void render(I2PAppContext ctx, OutputStream out, String filename) throws IOException { public static synchronized void render(I2PAppContext ctx, OutputStream out, String filename) throws IOException {
throw new UnsupportedOperationException();
/*****
long end = ctx.clock().now() - 60*1000; long end = ctx.clock().now() - 60*1000;
long start = end - 60*1000*SummaryListener.PERIODS; long start = end - 60*1000*SummaryListener.PERIODS;
try { try {
@@ -80,17 +82,34 @@ class SummaryRenderer {
//_log.error("Error rendering " + filename, ioe); //_log.error("Error rendering " + filename, ioe);
throw ioe; throw ioe;
} }
*****/
} }
public void render(OutputStream out) throws IOException { render(out, GraphHelper.DEFAULT_X, GraphHelper.DEFAULT_Y, public void render(OutputStream out) throws IOException { render(out, GraphHelper.DEFAULT_X, GraphHelper.DEFAULT_Y,
false, false, false, false, -1, 0, false); } false, false, false, false, -1, 0, false); }
/** /**
* Single graph.
*
* @param endp number of periods before now * @param endp number of periods before now
*/ */
public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid,
boolean hideTitle, boolean showEvents, int periodCount, boolean hideTitle, boolean showEvents, int periodCount,
int endp, boolean showCredit) throws IOException { int endp, boolean showCredit) throws IOException {
render(out, width, height, hideLegend, hideGrid, hideTitle,
showEvents, periodCount, endp, showCredit, null, null);
}
/**
* Single or two-data-source graph.
*
* @param lsnr2 2nd data source to plot on same graph, or null. Not recommended for events.
* @param titleOverride If non-null, overrides the title
* @since 0.9.6 consolidated from StatSummarizer for bw.combined
*/
public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid,
boolean hideTitle, boolean showEvents, int periodCount,
int endp, boolean showCredit, SummaryListener lsnr2, String titleOverride) throws IOException {
long end = _listener.now() - 75*1000; long end = _listener.now() - 75*1000;
long period = _listener.getRate().getPeriod(); long period = _listener.getRate().getPeriod();
if (endp > 0) if (endp > 0)
@@ -109,7 +128,9 @@ class SummaryRenderer {
if ((name.startsWith("bw.") || name.indexOf("Size") >= 0 || name.indexOf("Bps") >= 0 || name.indexOf("memory") >= 0) if ((name.startsWith("bw.") || name.indexOf("Size") >= 0 || name.indexOf("Bps") >= 0 || name.indexOf("memory") >= 0)
&& !showEvents) && !showEvents)
def.setBase(1024); def.setBase(1024);
if (!hideTitle) { if (titleOverride != null) {
def.setTitle(titleOverride);
} else if (!hideTitle) {
String title; String title;
String p; String p;
// we want the formatting and translation of formatDuration2(), except not zh, and not the &nbsp; // we want the formatting and translation of formatDuration2(), except not zh, and not the &nbsp;
@@ -146,14 +167,31 @@ class SummaryRenderer {
// def.vrule(started / 1000, RESTART_BAR_COLOR, _("Restart"), 4.0f); // def.vrule(started / 1000, RESTART_BAR_COLOR, _("Restart"), 4.0f);
def.datasource(plotName, path, plotName, SummaryListener.CF, _listener.getBackendName()); def.datasource(plotName, path, plotName, SummaryListener.CF, _listener.getBackendName());
if (descr.length() > 0) if (descr.length() > 0) {
def.area(plotName, Color.BLUE, descr + "\\r"); def.area(plotName, Color.BLUE, descr + "\\r");
else } else {
def.area(plotName, Color.BLUE); def.area(plotName, Color.BLUE);
}
if (!hideLegend) { if (!hideLegend) {
def.gprint(plotName, SummaryListener.CF, _("avg") + ": %.2f %s"); def.gprint(plotName, SummaryListener.CF, _("avg") + ": %.2f %s");
def.gprint(plotName, "MAX", ' ' + _("max") + ": %.2f %S"); def.gprint(plotName, "MAX", ' ' + _("max") + ": %.2f %S");
def.gprint(plotName, "LAST", ' ' + _("now") + ": %.2f %S\\r"); def.gprint(plotName, "LAST", ' ' + _("now") + ": %.2f %S\\r");
}
String plotName2 = null;
if (lsnr2 != null) {
String dsNames2[] = lsnr2.getData().getDsNames();
plotName2 = dsNames2[0];
String path2 = lsnr2.getData().getPath();
String descr2 = _(lsnr2.getRate().getRateStat().getDescription());
def.datasource(plotName2, path2, plotName2, SummaryListener.CF, lsnr2.getBackendName());
def.line(plotName2, Color.RED, descr2 + "\\r", 3);
if (!hideLegend) {
def.gprint(plotName2, SummaryListener.CF, _("avg") + ": %.2f %s");
def.gprint(plotName2, "MAX", ' ' + _("max") + ": %.2f %S");
def.gprint(plotName2, "LAST", ' ' + _("now") + ": %.2f %S\\r");
}
}
if (!hideLegend) {
// '07-Jul 21:09 UTC' with month name in the system locale // '07-Jul 21:09 UTC' with month name in the system locale
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM HH:mm"); SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM HH:mm");
Map<Long, String> events = ((RouterContext)_context).router().eventLog().getEvents(EventLog.STARTED, start); Map<Long, String> events = ((RouterContext)_context).router().eventLog().getEvents(EventLog.STARTED, start);

View File

@@ -60,15 +60,15 @@ if ( !rendered && ((rs != null) || fakeBw) ) {
if (str != null) try { periodCount = Integer.parseInt(str); } catch (NumberFormatException nfe) {} if (str != null) try { periodCount = Integer.parseInt(str); } catch (NumberFormatException nfe) {}
str = request.getParameter("end"); str = request.getParameter("end");
if (str != null) try { end = Integer.parseInt(str); } catch (NumberFormatException nfe) {} if (str != null) try { end = Integer.parseInt(str); } catch (NumberFormatException nfe) {}
boolean hideLegend = Boolean.valueOf(""+request.getParameter("hideLegend")).booleanValue(); boolean hideLegend = Boolean.parseBoolean((String) request.getParameter("hideLegend"));
boolean hideGrid = Boolean.valueOf(""+request.getParameter("hideGrid")).booleanValue(); boolean hideGrid = Boolean.parseBoolean((String) request.getParameter("hideGrid"));
boolean hideTitle = Boolean.valueOf(""+request.getParameter("hideTitle")).booleanValue(); boolean hideTitle = Boolean.parseBoolean((String) request.getParameter("hideTitle"));
boolean showEvents = Boolean.valueOf(""+request.getParameter("showEvents")).booleanValue(); boolean showEvents = Boolean.parseBoolean((String) request.getParameter("showEvents"));
boolean showCredit = false; boolean showCredit = false;
if (request.getParameter("showCredit") != null) if (request.getParameter("showCredit") != null)
showCredit = Boolean.valueOf(""+request.getParameter("showCredit")).booleanValue(); showCredit = Boolean.parseBoolean((String) request.getParameter("showCredit"));
if (fakeBw) if (fakeBw)
rendered = net.i2p.router.web.StatSummarizer.instance().renderRatePng(cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, showCredit); rendered = net.i2p.router.web.StatSummarizer.instance().renderRatePng(cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, end, showCredit);
else else
rendered = net.i2p.router.web.StatSummarizer.instance().renderPng(rate, cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, end, showCredit); rendered = net.i2p.router.web.StatSummarizer.instance().renderPng(rate, cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, end, showCredit);
} }

View File

@@ -1,3 +1,10 @@
2013-04-13 zzz
* Console: Add /graph support for bw.combined, consolidate
rendering code (ticket #890)
* i2psnark:
- Limit number of torrents displayed; add previous/next page buttons
- Only register one instance with UpdateManager
2013-04-10 zzz 2013-04-10 zzz
* Jetty: Upgrade to Jetty 7.6.10.v20130312 * Jetty: Upgrade to Jetty 7.6.10.v20130312
- Jetty build.xml improvements - Jetty build.xml improvements

View File

@@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */ /** deprecated */
public final static String ID = "Monotone"; public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION; public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 2; public final static long BUILD = 3;
/** for example "-test" */ /** for example "-test" */
public final static String EXTRA = ""; public final static String EXTRA = "";