diff --git a/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java index 15232fbcc..0bcaaf315 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java @@ -149,6 +149,10 @@ public class StatSummarizer implements Runnable { return false; } + /** + * This does the two-data bandwidth graph only. + * For all other graphs see SummaryRenderer + */ public boolean renderRatePng(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, boolean showCredit) throws IOException { long end = _context.clock().now() - 60*1000; if (width > GraphHelper.MAX_X) @@ -166,22 +170,22 @@ public class StatSummarizer implements Runnable { def.setTimePeriod(start/1000, 0); def.setLowerLimit(0d); def.setBaseValue(1024); - String title = "Bandwidth usage"; + String title = _("Bandwidth usage"); if (!hideTitle) def.setTitle(title); String sendName = SummaryListener.createName(_context, "bw.sendRate.60000"); String recvName = SummaryListener.createName(_context, "bw.recvRate.60000"); def.datasource(sendName, sendName, sendName, "AVERAGE", "MEMORY"); def.datasource(recvName, recvName, recvName, "AVERAGE", "MEMORY"); - def.area(sendName, Color.BLUE, "Outbound bytes/sec"); + 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.line(recvName, Color.RED, _("Inbound bytes/sec") + "@r", 3); //def.area(recvName, Color.RED, "Inbound bytes/sec@r"); if (!hideLegend) { - def.gprint(sendName, "AVERAGE", "out average: @2@sbytes/sec"); - def.gprint(sendName, "MAX", " max: @2@sbytes/sec@r"); - def.gprint(recvName, "AVERAGE", "in average: @2@sbytes/sec"); - def.gprint(recvName, "MAX", " max: @2@sbytes/sec@r"); + def.gprint(sendName, "AVERAGE", _("out average") + ": @2@s" + _("bytes/sec")); + def.gprint(sendName, "MAX", ' ' + _("max") + ": @2@s" + _("bytes/sec") + "@r"); + def.gprint(recvName, "AVERAGE", _("in average") + ": @2@s" + _("bytes/sec")); + def.gprint(recvName, "MAX", ' ' + _("max") + ": @2@s" + _("bytes/sec") + "@r"); } if (!showCredit) def.setShowSignature(false); @@ -248,4 +252,12 @@ public class StatSummarizer implements Runnable { } return rv; } + + /** translate a string */ + private String _(String s) { + // the RRD font doesn't have zh chars, at least on my system + if ("zh".equals(Messages.getLanguage(_context))) + return s; + return Messages.getString(s, _context); + } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java index f34659cdb..0d066233e 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java @@ -142,127 +142,3 @@ class SummaryListener implements RateSummaryListener { @Override public int hashCode() { return _rate.hashCode(); } } - -class SummaryRenderer { - private Log _log; - private SummaryListener _listener; - public SummaryRenderer(I2PAppContext ctx, SummaryListener lsnr) { - _log = ctx.logManager().getLog(SummaryRenderer.class); - _listener = lsnr; - } - - /** - * Render the stats as determined by the specified JRobin xml config, - * but note that this doesn't work on stock jvms, as it requires - * DOM level 3 load and store support. Perhaps we can bundle that, or - * specify who can get it from where, etc. - * - */ - public static synchronized void render(I2PAppContext ctx, OutputStream out, String filename) throws IOException { - long end = ctx.clock().now() - 60*1000; - long start = end - 60*1000*SummaryListener.PERIODS; - try { - RrdGraphDefTemplate template = new RrdGraphDefTemplate(filename); - RrdGraphDef def = template.getRrdGraphDef(); - def.setTimePeriod(start/1000, end/1000); // ignore the periods in the template - RrdGraph graph = new RrdGraph(def); - byte img[] = graph.getPNGBytes(); - out.write(img); - } catch (RrdException re) { - //_log.error("Error rendering " + filename, re); - throw new IOException("Error plotting: " + re.getMessage()); - } catch (IOException ioe) { - //_log.error("Error rendering " + filename, ioe); - throw ioe; - } - } - public void render(OutputStream out) throws IOException { render(out, -1, -1, false, false, false, false, -1, false); } - public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, boolean showCredit) throws IOException { - long end = _listener.now() - 60*1000; - if (periodCount <= 0) periodCount = SummaryListener.PERIODS; - if (periodCount > SummaryListener.PERIODS) - periodCount = SummaryListener.PERIODS; - long start = end - _listener.getRate().getPeriod()*periodCount; - //long begin = System.currentTimeMillis(); - try { - RrdGraphDef def = new RrdGraphDef(); - def.setTimePeriod(start/1000, 0); - def.setLowerLimit(0d); - String name = _listener.getRate().getRateStat().getName(); - // heuristic to set K=1024 - if ((name.startsWith("bw.") || name.indexOf("Size") >= 0 || name.indexOf("Bps") >= 0 || name.indexOf("memory") >= 0) - && !showEvents) - def.setBaseValue(1024); - String title = name; - if (showEvents) - title = title + " events in "; - else - title = title + " averaged for "; - title = title + DataHelper.formatDuration(_listener.getRate().getPeriod()); - if (!hideTitle) - def.setTitle(title); - String path = _listener.getData().getPath(); - String dsNames[] = _listener.getData().getDsNames(); - String plotName = null; - String descr = null; - if (showEvents) { - // include the average event count on the plot - plotName = dsNames[1]; - descr = "Events per period"; - } else { - // include the average value - plotName = dsNames[0]; - descr = _listener.getRate().getRateStat().getDescription(); - } - def.datasource(plotName, path, plotName, "AVERAGE", "MEMORY"); - def.area(plotName, Color.BLUE, descr + "@r"); - if (!hideLegend) { - def.gprint(plotName, "AVERAGE", "avg: @2@s"); - def.gprint(plotName, "MAX", " max: @2@s"); - def.gprint(plotName, "LAST", " now: @2@s@r"); - } - if (!showCredit) - def.setShowSignature(false); - /* - // these four lines set up a graph plotting both values and events on the same chart - // (but with the same coordinates, so the values may look pretty skewed) - def.datasource(dsNames[0], path, dsNames[0], "AVERAGE", "MEMORY"); - def.datasource(dsNames[1], path, dsNames[1], "AVERAGE", "MEMORY"); - def.area(dsNames[0], Color.BLUE, _listener.getRate().getRateStat().getDescription()); - def.line(dsNames[1], Color.RED, "Events per period"); - */ - if (hideLegend) - def.setShowLegend(false); - if (hideGrid) { - def.setGridX(false); - def.setGridY(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()); - RrdGraph graph = new RrdGraph(def); - //System.out.println("Graph created"); - byte data[] = null; - if ( (width <= 0) || (height <= 0) ) - data = graph.getPNGBytes(); - else - data = graph.getPNGBytes(width, height); - //long timeToPlot = System.currentTimeMillis() - begin; - out.write(data); - //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()); - } catch (RrdException re) { - _log.error("Error rendering", re); - throw new IOException("Error plotting: " + re.getMessage()); - } catch (IOException ioe) { - _log.error("Error rendering", ioe); - throw ioe; - } catch (OutOfMemoryError oom) { - _log.error("Error rendering", oom); - throw new IOException("Error plotting: " + oom.getMessage()); - } - } -} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java new file mode 100644 index 000000000..7ee62510b --- /dev/null +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java @@ -0,0 +1,170 @@ +package net.i2p.router.web; + +import java.awt.Color; +import java.io.IOException; +import java.io.OutputStream; + +import net.i2p.I2PAppContext; +import net.i2p.data.DataHelper; +import net.i2p.stat.Rate; +import net.i2p.stat.RateStat; +import net.i2p.stat.RateSummaryListener; +import net.i2p.util.Log; + +import org.jrobin.core.RrdBackendFactory; +import org.jrobin.core.RrdDb; +import org.jrobin.core.RrdDef; +import org.jrobin.core.RrdException; +import org.jrobin.core.RrdMemoryBackendFactory; +import org.jrobin.core.Sample; +import org.jrobin.graph.RrdGraph; +import org.jrobin.graph.RrdGraphDef; +import org.jrobin.graph.RrdGraphDefTemplate; + +class SummaryRenderer { + private Log _log; + private SummaryListener _listener; + private I2PAppContext _context; + + public SummaryRenderer(I2PAppContext ctx, SummaryListener lsnr) { + _log = ctx.logManager().getLog(SummaryRenderer.class); + _listener = lsnr; + _context = ctx; + } + + /** + * Render the stats as determined by the specified JRobin xml config, + * but note that this doesn't work on stock jvms, as it requires + * DOM level 3 load and store support. Perhaps we can bundle that, or + * specify who can get it from where, etc. + * + */ + public static synchronized void render(I2PAppContext ctx, OutputStream out, String filename) throws IOException { + long end = ctx.clock().now() - 60*1000; + long start = end - 60*1000*SummaryListener.PERIODS; + try { + RrdGraphDefTemplate template = new RrdGraphDefTemplate(filename); + RrdGraphDef def = template.getRrdGraphDef(); + def.setTimePeriod(start/1000, end/1000); // ignore the periods in the template + RrdGraph graph = new RrdGraph(def); + byte img[] = graph.getPNGBytes(); + out.write(img); + } catch (RrdException re) { + //_log.error("Error rendering " + filename, re); + throw new IOException("Error plotting: " + re.getMessage()); + } catch (IOException ioe) { + //_log.error("Error rendering " + filename, ioe); + throw ioe; + } + } + + public void render(OutputStream out) throws IOException { render(out, -1, -1, false, false, false, false, -1, false); } + + public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, boolean showCredit) throws IOException { + long end = _listener.now() - 60*1000; + if (periodCount <= 0) periodCount = SummaryListener.PERIODS; + if (periodCount > SummaryListener.PERIODS) + periodCount = SummaryListener.PERIODS; + long start = end - _listener.getRate().getPeriod()*periodCount; + //long begin = System.currentTimeMillis(); + try { + RrdGraphDef def = new RrdGraphDef(); + def.setTimePeriod(start/1000, 0); + def.setLowerLimit(0d); + String name = _listener.getRate().getRateStat().getName(); + // heuristic to set K=1024 + if ((name.startsWith("bw.") || name.indexOf("Size") >= 0 || name.indexOf("Bps") >= 0 || name.indexOf("memory") >= 0) + && !showEvents) + def.setBaseValue(1024); + if (!hideTitle) { + String title; + String p = DataHelper.formatDuration(_listener.getRate().getPeriod()); + if (showEvents) + title = name + ' ' + _("events in {0}", p); + else + title = name + ' ' + _("averaged for {0}", p); + def.setTitle(title); + } + String path = _listener.getData().getPath(); + String dsNames[] = _listener.getData().getDsNames(); + String plotName = null; + String descr = null; + if (showEvents) { + // include the average event count on the plot + plotName = dsNames[1]; + descr = _("Events per period"); + } else { + // include the average value + plotName = dsNames[0]; + descr = _listener.getRate().getRateStat().getDescription(); + } + def.datasource(plotName, path, plotName, "AVERAGE", "MEMORY"); + def.area(plotName, Color.BLUE, descr + "@r"); + if (!hideLegend) { + def.gprint(plotName, "AVERAGE", _("avg") + ": @2@s"); + def.gprint(plotName, "MAX", ' ' + _("max") + ": @2@s"); + def.gprint(plotName, "LAST", ' ' + _("now") + ": @2@s@r"); + } + if (!showCredit) + def.setShowSignature(false); + /* + // these four lines set up a graph plotting both values and events on the same chart + // (but with the same coordinates, so the values may look pretty skewed) + def.datasource(dsNames[0], path, dsNames[0], "AVERAGE", "MEMORY"); + def.datasource(dsNames[1], path, dsNames[1], "AVERAGE", "MEMORY"); + def.area(dsNames[0], Color.BLUE, _listener.getRate().getRateStat().getDescription()); + def.line(dsNames[1], Color.RED, "Events per period"); + */ + if (hideLegend) + def.setShowLegend(false); + if (hideGrid) { + def.setGridX(false); + def.setGridY(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()); + RrdGraph graph = new RrdGraph(def); + //System.out.println("Graph created"); + byte data[] = null; + if ( (width <= 0) || (height <= 0) ) + data = graph.getPNGBytes(); + else + data = graph.getPNGBytes(width, height); + //long timeToPlot = System.currentTimeMillis() - begin; + out.write(data); + //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()); + } catch (RrdException re) { + _log.error("Error rendering", re); + throw new IOException("Error plotting: " + re.getMessage()); + } catch (IOException ioe) { + _log.error("Error rendering", ioe); + throw ioe; + } catch (OutOfMemoryError oom) { + _log.error("Error rendering", oom); + throw new IOException("Error plotting: " + oom.getMessage()); + } + } + + /** translate a string */ + private String _(String s) { + // the RRD font doesn't have zh chars, at least on my system + if ("zh".equals(Messages.getLanguage(_context))) + return s; + return Messages.getString(s, _context); + } + + /** + * translate a string with a parameter + */ + private String _(String s, String o) { + // the RRD font doesn't have zh chars, at least on my system + if ("zh".equals(Messages.getLanguage(_context))) + return s.replace("{0}", o); + return Messages.getString(s, o, _context); + } +}