* Move StatsGenerator from router to routerconsole
* Move the unused AdminManager from router to the apps directory
This commit is contained in:
@ -6,7 +6,6 @@ import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.router.admin.AdminManager;
|
||||
import net.i2p.router.client.ClientManagerFacadeImpl;
|
||||
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
|
||||
import net.i2p.router.peermanager.Calculator;
|
||||
@ -35,7 +34,6 @@ import net.i2p.util.KeyRing;
|
||||
*/
|
||||
public class RouterContext extends I2PAppContext {
|
||||
private Router _router;
|
||||
private AdminManager _adminManager;
|
||||
private ClientManagerFacade _clientManagerFacade;
|
||||
private ClientMessagePool _clientMessagePool;
|
||||
private JobQueue _jobQueue;
|
||||
@ -91,7 +89,6 @@ public class RouterContext extends I2PAppContext {
|
||||
return envProps;
|
||||
}
|
||||
public void initAll() {
|
||||
//_adminManager = new AdminManager(this);
|
||||
if ("false".equals(getProperty("i2p.dummyClientFacade", "false")))
|
||||
_clientManagerFacade = new ClientManagerFacadeImpl(this);
|
||||
else
|
||||
@ -149,11 +146,6 @@ public class RouterContext extends I2PAppContext {
|
||||
/** convenience method for querying the router's ident */
|
||||
public Hash routerHash() { return _router.getRouterInfo().getIdentity().getHash(); }
|
||||
|
||||
/**
|
||||
* Controls a basic admin interface
|
||||
*
|
||||
*/
|
||||
public AdminManager adminManager() { return _adminManager; }
|
||||
/**
|
||||
* How are we coordinating clients for the router?
|
||||
*/
|
||||
|
@ -1,126 +0,0 @@
|
||||
package net.i2p.router.admin;
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by jrandom in 2003 and released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
* It probably won't make your computer catch on fire, or eat
|
||||
* your children, but it might. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Listen for connections on the specified port, and toss them onto the client manager's
|
||||
* set of connections once they are established.
|
||||
*
|
||||
* @author jrandom
|
||||
*/
|
||||
public class AdminListener implements Runnable {
|
||||
private Log _log;
|
||||
private RouterContext _context;
|
||||
private ServerSocket _socket;
|
||||
private int _port;
|
||||
private boolean _running;
|
||||
private long _nextFailDelay = 1000;
|
||||
|
||||
public AdminListener(RouterContext context, int port) {
|
||||
_context = context;
|
||||
_log = context.logManager().getLog(AdminListener.class);
|
||||
_port = port;
|
||||
_running = false;
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
// this works by taking advantage of the auto-retry mechanism in the
|
||||
// startup() loop (which we reset to wait 1s). by failing the socket
|
||||
// (through close()) and nulling it, we will have to try to build a new
|
||||
// serverSocket (using the *new* _port)
|
||||
_nextFailDelay = 1000;
|
||||
ServerSocket s = _socket;
|
||||
try {
|
||||
_socket = null;
|
||||
s.close();
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
|
||||
public void setPort(int port) { _port = port; }
|
||||
public int getPort() { return _port; }
|
||||
|
||||
/** max time to bind */
|
||||
private final static int MAX_FAIL_DELAY = 5*60*1000;
|
||||
|
||||
/**
|
||||
* Start up the socket listener, listens for connections, and
|
||||
* fires those connections off via {@link #runConnection runConnection}.
|
||||
* This only returns if the socket cannot be opened or there is a catastrophic
|
||||
* failure.
|
||||
*
|
||||
*/
|
||||
public void startup() {
|
||||
_running = true;
|
||||
int curDelay = 0;
|
||||
while ( (_running) && (curDelay < MAX_FAIL_DELAY) ) {
|
||||
try {
|
||||
_log.info("Starting up listening for connections on port " + _port);
|
||||
_socket = new ServerSocket(_port);
|
||||
curDelay = 0;
|
||||
while (_running && (_socket != null) ) {
|
||||
try {
|
||||
Socket socket = _socket.accept();
|
||||
_log.debug("Connection received");
|
||||
runConnection(socket);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Server error accepting", ioe);
|
||||
} catch (Throwable t) {
|
||||
_log.error("Fatal error running client listener - killing the thread!", t);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error listening on port " + _port, ioe);
|
||||
}
|
||||
|
||||
if (_socket != null) {
|
||||
try { _socket.close(); } catch (IOException ioe) {}
|
||||
_socket = null;
|
||||
}
|
||||
|
||||
_log.error("Error listening, waiting " + _nextFailDelay + "ms before we try again");
|
||||
try { Thread.sleep(_nextFailDelay); } catch (InterruptedException ie) {}
|
||||
curDelay += _nextFailDelay;
|
||||
_nextFailDelay *= 5;
|
||||
}
|
||||
|
||||
_log.error("CANCELING ADMIN LISTENER. delay = " + curDelay, new Exception("ADMIN LISTENER cancelled!!!"));
|
||||
_running = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the connection by passing it off to an AdminRunner
|
||||
*
|
||||
*/
|
||||
protected void runConnection(Socket socket) throws IOException {
|
||||
AdminRunner runner = new AdminRunner(_context, socket);
|
||||
I2PThread t = new I2PThread(runner);
|
||||
t.setName("Admin Runner");
|
||||
//t.setPriority(Thread.MIN_PRIORITY);
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
_running = false;
|
||||
if (_socket != null) try {
|
||||
_socket.close();
|
||||
_socket = null;
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
public void run() { startup(); }
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package net.i2p.router.admin;
|
||||
|
||||
import java.io.Writer;
|
||||
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.Service;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class AdminManager implements Service {
|
||||
private Log _log;
|
||||
private RouterContext _context;
|
||||
public final static String PARAM_ADMIN_PORT = "router.adminPort";
|
||||
public final static int DEFAULT_ADMIN_PORT = 7655;
|
||||
|
||||
private AdminListener _listener;
|
||||
|
||||
public AdminManager(RouterContext context) {
|
||||
_context = context;
|
||||
_log = context.logManager().getLog(AdminManager.class);
|
||||
}
|
||||
|
||||
public void renderStatusHTML(Writer out) { }
|
||||
|
||||
public void shutdown() {
|
||||
if (_listener != null) {
|
||||
_log.info("Shutting down admin listener");
|
||||
_listener.shutdown();
|
||||
_listener = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
startup();
|
||||
}
|
||||
|
||||
public void startup() {
|
||||
int port = DEFAULT_ADMIN_PORT;
|
||||
String str = _context.router().getConfigSetting(PARAM_ADMIN_PORT);
|
||||
if (str != null) {
|
||||
try {
|
||||
int val = Integer.parseInt(str);
|
||||
port = val;
|
||||
_log.info("Starting up admin listener on port " + port);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.warn("Invalid admin port specified [" + str + "], using the default " + DEFAULT_ADMIN_PORT, nfe);
|
||||
}
|
||||
} else {
|
||||
_log.warn("Router admin port not specified, using the default " + DEFAULT_ADMIN_PORT);
|
||||
}
|
||||
startup(port);
|
||||
}
|
||||
|
||||
private void startup(int port) {
|
||||
if (_listener == null) {
|
||||
_listener = new AdminListener(_context, port);
|
||||
I2PThread t = new I2PThread(_listener);
|
||||
t.setName("Admin Listener:" + port);
|
||||
t.setDaemon(true);
|
||||
//t.setPriority(Thread.MIN_PRIORITY);
|
||||
t.start();
|
||||
} else {
|
||||
_listener.setPort(port);
|
||||
_listener.restart();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,150 +0,0 @@
|
||||
package net.i2p.router.admin;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.Socket;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
class AdminRunner implements Runnable {
|
||||
private Log _log;
|
||||
private RouterContext _context;
|
||||
private Socket _socket;
|
||||
private StatsGenerator _generator;
|
||||
|
||||
public AdminRunner(RouterContext context, Socket socket) {
|
||||
_context = context;
|
||||
_log = context.logManager().getLog(AdminRunner.class);
|
||||
_socket = socket;
|
||||
_generator = new StatsGenerator(context);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
|
||||
OutputStream out = _socket.getOutputStream();
|
||||
|
||||
String command = in.readLine();
|
||||
runCommand(command, out);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error running admin command", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
private void runCommand(String command, OutputStream out) throws IOException {
|
||||
_log.debug("Command [" + command + "]");
|
||||
if (command.indexOf("favicon") >= 0) {
|
||||
reply(out, "this is not a website");
|
||||
} else if ( (command.indexOf("routerStats.html") >= 0) || (command.indexOf("oldstats.jsp") >= 0) ) {
|
||||
try {
|
||||
out.write("HTTP/1.1 200 OK\nConnection: close\nCache-control: no-cache\nContent-type: text/html\n\n".getBytes());
|
||||
_generator.generateStatsPage(new OutputStreamWriter(out));
|
||||
out.close();
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error writing out the admin reply");
|
||||
throw ioe;
|
||||
}
|
||||
} else if (command.indexOf("/profile/") >= 0) {
|
||||
replyText(out, getProfile(command));
|
||||
} else if (command.indexOf("/shutdown") >= 0) {
|
||||
reply(out, shutdown(command));
|
||||
} else if (true || command.indexOf("routerConsole.html") > 0) {
|
||||
try {
|
||||
out.write("HTTP/1.1 200 OK\nConnection: close\nCache-control: no-cache\nContent-type: text/html\n\n".getBytes());
|
||||
_context.router().renderStatusHTML(new OutputStreamWriter(out));
|
||||
out.close();
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error writing out the admin reply");
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void reply(OutputStream out, String content) throws IOException {
|
||||
StringBuilder reply = new StringBuilder(10240);
|
||||
reply.append("HTTP/1.1 200 OK\n");
|
||||
reply.append("Connection: close\n");
|
||||
reply.append("Cache-control: no-cache\n");
|
||||
reply.append("Content-type: text/html\n\n");
|
||||
reply.append(content);
|
||||
try {
|
||||
out.write(reply.toString().getBytes());
|
||||
out.close();
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error writing out the admin reply:\n" + content);
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
|
||||
private void replyText(OutputStream out, String content) throws IOException {
|
||||
StringBuilder reply = new StringBuilder(10240);
|
||||
reply.append("HTTP/1.1 200 OK\n");
|
||||
reply.append("Connection: close\n");
|
||||
reply.append("Cache-control: no-cache\n");
|
||||
reply.append("Content-type: text/plain\n\n");
|
||||
reply.append(content);
|
||||
try {
|
||||
out.write(reply.toString().getBytes());
|
||||
out.close();
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error writing out the admin reply:\n" + content);
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
|
||||
private String getProfile(String cmd) {
|
||||
Set peers = _context.profileOrganizer().selectAllPeers();
|
||||
for (Iterator iter = peers.iterator(); iter.hasNext(); ) {
|
||||
Hash peer = (Hash)iter.next();
|
||||
if (cmd.indexOf(peer.toBase64().substring(0,10)) >= 0) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(64*1024);
|
||||
_context.profileOrganizer().exportProfile(peer, baos);
|
||||
return new String(baos.toByteArray());
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error exporting the profile", ioe);
|
||||
return "Error exporting the peer profile\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "No such peer is being profiled\n";
|
||||
}
|
||||
|
||||
private static final String SHUTDOWN_PASSWORD_PROP = "router.shutdownPassword";
|
||||
private String shutdown(String cmd) {
|
||||
String password = _context.router().getConfigSetting(SHUTDOWN_PASSWORD_PROP);
|
||||
if (password == null)
|
||||
password = _context.getProperty(SHUTDOWN_PASSWORD_PROP);
|
||||
if (password == null)
|
||||
return "No shutdown password specified in the config or context - <b>REFUSING SHUTDOWN</b>." +
|
||||
"<a href=\"/routerConsole.html\">back</a>";
|
||||
if (cmd.indexOf(password) > 0) {
|
||||
I2PThread t = new I2PThread(new Runnable() {
|
||||
public void run() {
|
||||
try { Thread.sleep(30*1000); } catch (InterruptedException ie) {}
|
||||
_context.router().shutdown(Router.EXIT_HARD);
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
return "Shutdown request accepted. Killing the router in 30 seconds";
|
||||
} else {
|
||||
return "Incorrect shutdown password specified. Please edit your router.config appropriately." +
|
||||
"<a href=\"/routerConsole.html\">back</a>";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,238 +0,0 @@
|
||||
package net.i2p.router.admin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.stat.Frequency;
|
||||
import net.i2p.stat.FrequencyStat;
|
||||
import net.i2p.stat.Rate;
|
||||
import net.i2p.stat.RateStat;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Dump the stats to the web admin interface
|
||||
*/
|
||||
public class StatsGenerator {
|
||||
private Log _log;
|
||||
private RouterContext _context;
|
||||
public StatsGenerator(RouterContext context) {
|
||||
_context = context;
|
||||
_log = context.logManager().getLog(StatsGenerator.class);
|
||||
}
|
||||
|
||||
public void generateStatsPage(Writer out) throws IOException {
|
||||
StringBuilder buf = new StringBuilder(16*1024);
|
||||
buf.append("<div class=\"joblog\"><form action=\"/oldstats.jsp\">");
|
||||
buf.append("<select name=\"go\" onChange='location.href=this.value'>");
|
||||
out.write(buf.toString());
|
||||
buf.setLength(0);
|
||||
|
||||
Map groups = _context.statManager().getStatsByGroup();
|
||||
for (Iterator iter = groups.entrySet().iterator(); iter.hasNext(); ) {
|
||||
Map.Entry entry = (Map.Entry)iter.next();
|
||||
String group = (String)entry.getKey();
|
||||
Set stats = (Set)entry.getValue();
|
||||
buf.append("<option value=\"/oldstats.jsp#").append(group).append("\">");
|
||||
buf.append(group).append("</option>\n");
|
||||
for (Iterator statIter = stats.iterator(); statIter.hasNext(); ) {
|
||||
String stat = (String)statIter.next();
|
||||
buf.append("<option value=\"/oldstats.jsp#");
|
||||
buf.append(stat);
|
||||
buf.append("\">...");
|
||||
buf.append(stat);
|
||||
buf.append("</option>\n");
|
||||
}
|
||||
out.write(buf.toString());
|
||||
buf.setLength(0);
|
||||
}
|
||||
buf.append("</select> <input type=\"submit\" value=\"GO\" />");
|
||||
buf.append("</form>");
|
||||
|
||||
buf.append("Statistics gathered during this router's uptime (");
|
||||
long uptime = _context.router().getUptime();
|
||||
buf.append(DataHelper.formatDuration(uptime));
|
||||
buf.append("). The data gathered is quantized over a 1 minute period, so should just be used as an estimate<p />");
|
||||
|
||||
out.write(buf.toString());
|
||||
buf.setLength(0);
|
||||
|
||||
for (Iterator iter = groups.keySet().iterator(); iter.hasNext(); ) {
|
||||
String group = (String)iter.next();
|
||||
Set stats = (Set)groups.get(group);
|
||||
buf.append("<h3><a name=\"");
|
||||
buf.append(group);
|
||||
buf.append("\">");
|
||||
buf.append(group);
|
||||
buf.append("</a></h3>");
|
||||
buf.append("<ul>");
|
||||
out.write(buf.toString());
|
||||
buf.setLength(0);
|
||||
for (Iterator statIter = stats.iterator(); statIter.hasNext(); ) {
|
||||
String stat = (String)statIter.next();
|
||||
buf.append("<li><b><a name=\"");
|
||||
buf.append(stat);
|
||||
buf.append("\">");
|
||||
buf.append(stat);
|
||||
buf.append("</a></b><br />");
|
||||
if (_context.statManager().isFrequency(stat))
|
||||
renderFrequency(stat, buf);
|
||||
else
|
||||
renderRate(stat, buf);
|
||||
out.write(buf.toString());
|
||||
buf.setLength(0);
|
||||
}
|
||||
out.write("</ul><hr />");
|
||||
}
|
||||
out.flush();
|
||||
}
|
||||
|
||||
private void renderFrequency(String name, StringBuilder buf) {
|
||||
FrequencyStat freq = _context.statManager().getFrequency(name);
|
||||
buf.append("<i>");
|
||||
buf.append(freq.getDescription());
|
||||
buf.append("</i><br />");
|
||||
long uptime = _context.router().getUptime();
|
||||
long periods[] = freq.getPeriods();
|
||||
Arrays.sort(periods);
|
||||
for (int i = 0; i < periods.length; i++) {
|
||||
if (periods[i] > uptime)
|
||||
break;
|
||||
renderPeriod(buf, periods[i], "frequency");
|
||||
Frequency curFreq = freq.getFrequency(periods[i]);
|
||||
buf.append(" <i>avg per period:</i> (");
|
||||
buf.append(num(curFreq.getAverageEventsPerPeriod()));
|
||||
buf.append(", max ");
|
||||
buf.append(num(curFreq.getMaxAverageEventsPerPeriod()));
|
||||
if ( (curFreq.getMaxAverageEventsPerPeriod() > 0) && (curFreq.getAverageEventsPerPeriod() > 0) ) {
|
||||
buf.append(", current is ");
|
||||
buf.append(pct(curFreq.getAverageEventsPerPeriod()/curFreq.getMaxAverageEventsPerPeriod()));
|
||||
buf.append(" of max");
|
||||
}
|
||||
buf.append(")");
|
||||
//buf.append(" <i>avg interval between updates:</i> (").append(num(curFreq.getAverageInterval())).append("ms, min ");
|
||||
//buf.append(num(curFreq.getMinAverageInterval())).append("ms)");
|
||||
buf.append(" <i>strict average per period:</i> ");
|
||||
buf.append(num(curFreq.getStrictAverageEventsPerPeriod()));
|
||||
buf.append(" events (averaged ");
|
||||
buf.append(" using the lifetime of ");
|
||||
buf.append(curFreq.getEventCount());
|
||||
buf.append(" events)");
|
||||
buf.append("<br />");
|
||||
}
|
||||
buf.append("<br />");
|
||||
}
|
||||
|
||||
private void renderRate(String name, StringBuilder buf) {
|
||||
RateStat rate = _context.statManager().getRate(name);
|
||||
String d = rate.getDescription();
|
||||
if (! "".equals(d)) {
|
||||
buf.append("<i>");
|
||||
buf.append(d);
|
||||
buf.append("</i><br />");
|
||||
}
|
||||
if (rate.getLifetimeEventCount() <= 0) {
|
||||
buf.append("No lifetime events<br /> <br />");
|
||||
return;
|
||||
}
|
||||
long now = _context.clock().now();
|
||||
long periods[] = rate.getPeriods();
|
||||
Arrays.sort(periods);
|
||||
buf.append("<ul>");
|
||||
for (int i = 0; i < periods.length; i++) {
|
||||
Rate curRate = rate.getRate(periods[i]);
|
||||
if (curRate.getLastCoalesceDate() <= curRate.getCreationDate())
|
||||
break;
|
||||
buf.append("<li>");
|
||||
renderPeriod(buf, periods[i], "rate");
|
||||
if (curRate.getLastEventCount() > 0) {
|
||||
buf.append( "<i>avg value:</i> (");
|
||||
buf.append(num(curRate.getAverageValue()));
|
||||
buf.append(" peak ");
|
||||
buf.append(num(curRate.getExtremeAverageValue()));
|
||||
buf.append(", [");
|
||||
buf.append(pct(curRate.getPercentageOfExtremeValue()));
|
||||
buf.append(" of max");
|
||||
buf.append(", and ");
|
||||
buf.append(pct(curRate.getPercentageOfLifetimeValue()));
|
||||
buf.append(" of lifetime average]");
|
||||
|
||||
buf.append(")");
|
||||
buf.append(" <i>highest total period value:</i> (");
|
||||
buf.append(num(curRate.getExtremeTotalValue()));
|
||||
buf.append(")");
|
||||
if (curRate.getLifetimeTotalEventTime() > 0) {
|
||||
buf.append(" <i>saturation:</i> (");
|
||||
buf.append(pct(curRate.getLastEventSaturation()));
|
||||
buf.append(")");
|
||||
buf.append(" <i>saturated limit:</i> (");
|
||||
buf.append(num(curRate.getLastSaturationLimit()));
|
||||
buf.append(")");
|
||||
buf.append(" <i>peak saturation:</i> (");
|
||||
buf.append(pct(curRate.getExtremeEventSaturation()));
|
||||
buf.append(")");
|
||||
buf.append(" <i>peak saturated limit:</i> (");
|
||||
buf.append(num(curRate.getExtremeSaturationLimit()));
|
||||
buf.append(")");
|
||||
}
|
||||
buf.append(" <i>events:</i> ");
|
||||
buf.append(curRate.getLastEventCount());
|
||||
buf.append(" <i>in this period which ended:</i> ");
|
||||
buf.append(DataHelper.formatDuration(now - curRate.getLastCoalesceDate()));
|
||||
buf.append(" ago ");
|
||||
} else {
|
||||
buf.append(" <i>No events</i> ");
|
||||
}
|
||||
long numPeriods = curRate.getLifetimePeriods();
|
||||
if (numPeriods > 0) {
|
||||
double avgFrequency = curRate.getLifetimeEventCount() / (double)numPeriods;
|
||||
double peakFrequency = curRate.getExtremeEventCount();
|
||||
buf.append(" (lifetime average: ");
|
||||
buf.append(num(avgFrequency));
|
||||
buf.append(", peak average: ");
|
||||
buf.append(curRate.getExtremeEventCount());
|
||||
buf.append(")");
|
||||
}
|
||||
if (curRate.getSummaryListener() != null) {
|
||||
buf.append(" <a href=\"viewstat.jsp?stat=").append(name);
|
||||
buf.append("&period=").append(periods[i]);
|
||||
buf.append("\" title=\"Render summarized data\">render</a>");
|
||||
buf.append(" <a href=\"viewstat.jsp?stat=").append(name);
|
||||
buf.append("&period=").append(periods[i]).append("&showEvents=true\" title=\"Render summarized event counts\">events</a>");
|
||||
buf.append(" (as <a href=\"viewstat.jsp?stat=").append(name);
|
||||
buf.append("&period=").append(periods[i]);
|
||||
buf.append("&format=xml\" title=\"Dump stat history as XML\">XML</a>");
|
||||
buf.append(" in a format <a href=\"http://people.ee.ethz.ch/~oetiker/webtools/rrdtool\">RRDTool</a> understands)");
|
||||
}
|
||||
buf.append("</li>");
|
||||
}
|
||||
// Display the strict average
|
||||
buf.append("<li><b>lifetime average value:</b> ");
|
||||
buf.append(num(rate.getLifetimeAverageValue()));
|
||||
buf.append(" over ");
|
||||
buf.append(rate.getLifetimeEventCount());
|
||||
buf.append(" events<br /></li>");
|
||||
buf.append("</ul>");
|
||||
buf.append("<br />");
|
||||
}
|
||||
|
||||
private static void renderPeriod(StringBuilder buf, long period, String name) {
|
||||
buf.append("<b>");
|
||||
buf.append(DataHelper.formatDuration(period));
|
||||
buf.append(" ");
|
||||
buf.append(name);
|
||||
buf.append(":</b> ");
|
||||
}
|
||||
|
||||
private final static DecimalFormat _fmt = new DecimalFormat("###,##0.00");
|
||||
private final static String num(double num) { synchronized (_fmt) { return _fmt.format(num); } }
|
||||
|
||||
private final static DecimalFormat _pct = new DecimalFormat("#0.00%");
|
||||
private final static String pct(double num) { synchronized (_pct) { return _pct.format(num); } }
|
||||
}
|
Reference in New Issue
Block a user