* helper to read the last few lines of a textfile

* use that to render the last few lines of the wrapper log on /logs.jsp (for the on demand stack trace)
* thread creation / finalization logging
* support a hard restart (stop immediately and restart the JVM) - useful for rerunning clients.config (etc)
* systray when not supported
This commit is contained in:
jrandom
2004-08-24 18:02:48 +00:00
committed by zzz
parent 71577c9b0e
commit e81c1df19f
7 changed files with 92 additions and 9 deletions

View File

@ -28,15 +28,28 @@ public class ConfigServiceHandler extends FormHandler {
} else if ("Cancel graceful shutdown".equals(_action)) { } else if ("Cancel graceful shutdown".equals(_action)) {
_context.router().cancelGracefulShutdown(); _context.router().cancelGracefulShutdown();
addFormNotice("Graceful shutdown cancelled"); addFormNotice("Graceful shutdown cancelled");
} else if ("Hard restart".equals(_action)) {
_context.router().shutdown(Router.EXIT_HARD_RESTART);
addFormNotice("Hard restart requested");
} else if ("Dump threads".equals(_action)) { } else if ("Dump threads".equals(_action)) {
WrapperManager.requestThreadDump(); WrapperManager.requestThreadDump();
addFormNotice("Threads dumped to logs/wrapper.log"); addFormNotice("Threads dumped to logs/wrapper.log");
} else if ("Show systray icon".equals(_action)) { } else if ("Show systray icon".equals(_action)) {
SysTray.getInstance().show(); SysTray tray = SysTray.getInstance();
addFormNotice("Systray icon enabled (if possible)"); if (tray != null) {
tray.show();
addFormNotice("Systray enabled");
} else {
addFormNotice("Systray not supported on this platform");
}
} else if ("Hide systray icon".equals(_action)) { } else if ("Hide systray icon".equals(_action)) {
SysTray.getInstance().hide(); SysTray tray = SysTray.getInstance();
addFormNotice("Systray icon disabled"); if (tray != null) {
tray.hide();
addFormNotice("Systray disabled");
} else {
addFormNotice("Systray not supported on this platform");
}
} else { } else {
addFormNotice("Blah blah blah. whatever. I'm not going to " + _action); addFormNotice("Blah blah blah. whatever. I'm not going to " + _action);
} }

View File

@ -4,6 +4,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import net.i2p.data.DataHelper;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
public class LogsHelper { public class LogsHelper {
@ -39,4 +40,12 @@ public class LogsHelper {
return buf.toString(); return buf.toString();
} }
public String getServiceLogs() {
String str = DataHelper.readTextFile("logs/wrapper.log", 500);
if (str == null)
return "";
else
return "<pre>" + str + "</pre>";
}
} }

View File

@ -31,6 +31,7 @@
<input type="submit" name="action" value="Shutdown gracefully" /> <input type="submit" name="action" value="Shutdown gracefully" />
<input type="submit" name="action" value="Shutdown immediately" /> <input type="submit" name="action" value="Shutdown immediately" />
<input type="submit" name="action" value="Cancel graceful shutdown" /> <input type="submit" name="action" value="Cancel graceful shutdown" />
<input type="submit" name="action" value="Hard restart" />
<h4>Systray integration</h4> <h4>Systray integration</h4>
On the windows platform, there is a small application to sit in the system On the windows platform, there is a small application to sit in the system
tray, allowing you to view the router's status (later on, I2P client applications tray, allowing you to view the router's status (later on, I2P client applications
@ -50,7 +51,8 @@
<input type="submit" name="action" value="Don't run I2P on startup" /> <input type="submit" name="action" value="Don't run I2P on startup" />
<h4>Debugging</h4> <h4>Debugging</h4>
At times, it may be helpful to debug I2P by getting a thread dump. To do so, At times, it may be helpful to debug I2P by getting a thread dump. To do so,
please select the following option and review the thread dumped to logs/wrapper.log.<br /> please select the following option and review the thread dumped to
<a href="logs.jsp#servicelogs">logs/wrapper.log</a>.<br />
<input type="submit" name="action" value="Dump threads" /> <input type="submit" name="action" value="Dump threads" />
</form> </form>
</div> </div>

View File

@ -13,7 +13,11 @@
<div class="main" id="main"> <div class="main" id="main">
<jsp:useBean class="net.i2p.router.web.LogsHelper" id="logsHelper" scope="request" /> <jsp:useBean class="net.i2p.router.web.LogsHelper" id="logsHelper" scope="request" />
<jsp:setProperty name="logsHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" /> <jsp:setProperty name="logsHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<h4>Router logs:</h4>
<jsp:getProperty name="logsHelper" property="logs" /> <jsp:getProperty name="logsHelper" property="logs" />
<hr />
<h4>Service logs:</h4><a name="servicelogs"> </a>
<jsp:getProperty name="logsHelper" property="serviceLogs" />
</div> </div>
</body> </body>

View File

@ -606,4 +606,34 @@ public class DataHelper {
// * (((double) rv.length) / ((double) orig.length)) + "% savings)"); // * (((double) rv.length) / ((double) orig.length)) + "% savings)");
return rv; return rv;
} }
/**
* Read in the last few lines of a (newline delimited) textfile, or null if
* the file doesn't exist.
*
*/
public static String readTextFile(String filename, int maxNumLines) {
File f = new File(filename);
if (!f.exists()) return null;
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
BufferedReader in = new BufferedReader(new InputStreamReader(fis));
List lines = new ArrayList(maxNumLines);
String line = null;
while ( (line = in.readLine()) != null) {
lines.add(line);
while (lines.size() > maxNumLines)
lines.remove(0);
}
StringBuffer buf = new StringBuffer(lines.size() * 80);
for (int i = 0; i < lines.size(); i++)
buf.append((String)lines.get(i)).append('\n');
return buf.toString();
} catch (IOException ioe) {
return null;
} finally {
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
}
}
} }

View File

@ -20,33 +20,51 @@ import java.util.Set;
* *
*/ */
public class I2PThread extends Thread { public class I2PThread extends Thread {
private static Log _log; private static volatile Log _log;
private static Set _listeners = new HashSet(4); private static Set _listeners = new HashSet(4);
private String _name;
private Exception _createdBy;
public I2PThread() { public I2PThread() {
super(); super();
if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
_createdBy = new Exception("Created by");
} }
public I2PThread(String name) { public I2PThread(String name) {
super(name); super(name);
if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
_createdBy = new Exception("Created by");
} }
public I2PThread(Runnable r) { public I2PThread(Runnable r) {
super(r); super(r);
if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
_createdBy = new Exception("Created by");
} }
public I2PThread(Runnable r, String name) { public I2PThread(Runnable r, String name) {
super(r, name); super(r, name);
if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
_createdBy = new Exception("Created by");
}
private void log(int level, String msg) { log(level, msg, null); }
private void log(int level, String msg, Throwable t) {
// we cant assume log is created
if (_log == null) _log = new Log(I2PThread.class);
if (_log.shouldLog(level))
_log.log(level, msg, t);
} }
public void run() { public void run() {
_name = Thread.currentThread().getName();
log(Log.DEBUG, "New thread started: " + _name, _createdBy);
try { try {
super.run(); super.run();
} catch (Throwable t) { } catch (Throwable t) {
try { try {
// we cant assume log is created log(Log.CRIT, "Killing thread " + getName(), t);
if (_log == null) _log = new Log(I2PThread.class);
_log.log(Log.CRIT, "Killing thread " + getName(), t);
} catch (Throwable woof) { } catch (Throwable woof) {
System.err.println("Died within the OOM itself"); System.err.println("Died within the OOM itself");
t.printStackTrace(); t.printStackTrace();
@ -54,6 +72,12 @@ public class I2PThread extends Thread {
if (t instanceof OutOfMemoryError) if (t instanceof OutOfMemoryError)
fireOOM((OutOfMemoryError)t); fireOOM((OutOfMemoryError)t);
} }
log(Log.DEBUG, "Thread finished gracefully: " + _name);
}
protected void finalize() throws Throwable {
log(Log.DEBUG, "Thread finalized: " + _name);
super.finalize();
} }
private void fireOOM(OutOfMemoryError oom) { private void fireOOM(OutOfMemoryError oom) {

View File

@ -539,6 +539,7 @@ public class Router {
public static final int EXIT_GRACEFUL = 2; public static final int EXIT_GRACEFUL = 2;
public static final int EXIT_HARD = 3; public static final int EXIT_HARD = 3;
public static final int EXIT_OOM = 10; public static final int EXIT_OOM = 10;
public static final int EXIT_HARD_RESTART = 4;
public void shutdown(int exitCode) { public void shutdown(int exitCode) {
_isAlive = false; _isAlive = false;