diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java index 51f04d48c348ebc8cb1e09606c30045ad580cff8..83d354008b56dd8a1fa6101df886f54c63735a68 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java @@ -28,15 +28,28 @@ public class ConfigServiceHandler extends FormHandler { } else if ("Cancel graceful shutdown".equals(_action)) { _context.router().cancelGracefulShutdown(); 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)) { WrapperManager.requestThreadDump(); addFormNotice("Threads dumped to logs/wrapper.log"); } else if ("Show systray icon".equals(_action)) { - SysTray.getInstance().show(); - addFormNotice("Systray icon enabled (if possible)"); + SysTray tray = SysTray.getInstance(); + if (tray != null) { + tray.show(); + addFormNotice("Systray enabled"); + } else { + addFormNotice("Systray not supported on this platform"); + } } else if ("Hide systray icon".equals(_action)) { - SysTray.getInstance().hide(); - addFormNotice("Systray icon disabled"); + SysTray tray = SysTray.getInstance(); + if (tray != null) { + tray.hide(); + addFormNotice("Systray disabled"); + } else { + addFormNotice("Systray not supported on this platform"); + } } else { addFormNotice("Blah blah blah. whatever. I'm not going to " + _action); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java index ab069ec769bdf4387700504ebce0401ee4302564..ee8299bfb7bd59e2a617e19b803ac094780b7a65 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java @@ -4,6 +4,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.List; +import net.i2p.data.DataHelper; import net.i2p.router.RouterContext; public class LogsHelper { @@ -39,4 +40,12 @@ public class LogsHelper { return buf.toString(); } + + public String getServiceLogs() { + String str = DataHelper.readTextFile("logs/wrapper.log", 500); + if (str == null) + return ""; + else + return "<pre>" + str + "</pre>"; + } } diff --git a/apps/routerconsole/jsp/configservice.jsp b/apps/routerconsole/jsp/configservice.jsp index 7dd44a452a494f7ffae1c9a97b4edc52457eaa5a..6728c1862b4383f9ebb7a1ea6ed304cc3755dda9 100644 --- a/apps/routerconsole/jsp/configservice.jsp +++ b/apps/routerconsole/jsp/configservice.jsp @@ -31,6 +31,7 @@ <input type="submit" name="action" value="Shutdown gracefully" /> <input type="submit" name="action" value="Shutdown immediately" /> <input type="submit" name="action" value="Cancel graceful shutdown" /> + <input type="submit" name="action" value="Hard restart" /> <h4>Systray integration</h4> 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 @@ -50,7 +51,8 @@ <input type="submit" name="action" value="Don't run I2P on startup" /> <h4>Debugging</h4> 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" /> </form> </div> diff --git a/apps/routerconsole/jsp/logs.jsp b/apps/routerconsole/jsp/logs.jsp index f46f2c7d63690bdc101cbe6e1c6aac668b9d5d16..10b61c1155ba8362db0f0ea7f88d73374c4d19e9 100644 --- a/apps/routerconsole/jsp/logs.jsp +++ b/apps/routerconsole/jsp/logs.jsp @@ -13,7 +13,11 @@ <div class="main" id="main"> <jsp:useBean class="net.i2p.router.web.LogsHelper" id="logsHelper" scope="request" /> <jsp:setProperty name="logsHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" /> + <h4>Router logs:</h4> <jsp:getProperty name="logsHelper" property="logs" /> + <hr /> + <h4>Service logs:</h4><a name="servicelogs"> </a> + <jsp:getProperty name="logsHelper" property="serviceLogs" /> </div> </body> diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java index 738d84bc0af92b0f913007f441c1125ad8cc2fc9..0c4f6e3bd8433168b6505b9ec924350c19ba532e 100644 --- a/core/java/src/net/i2p/data/DataHelper.java +++ b/core/java/src/net/i2p/data/DataHelper.java @@ -606,4 +606,34 @@ public class DataHelper { // * (((double) rv.length) / ((double) orig.length)) + "% savings)"); 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) {} + } + } } diff --git a/core/java/src/net/i2p/util/I2PThread.java b/core/java/src/net/i2p/util/I2PThread.java index 88d89da74ae5e15c1cdd2d2e207ca1f1e8acb3c1..b4bd8d740ce09e40272485c99d48d4e468d6847d 100644 --- a/core/java/src/net/i2p/util/I2PThread.java +++ b/core/java/src/net/i2p/util/I2PThread.java @@ -20,33 +20,51 @@ import java.util.Set; * */ public class I2PThread extends Thread { - private static Log _log; + private static volatile Log _log; private static Set _listeners = new HashSet(4); + private String _name; + private Exception _createdBy; public I2PThread() { super(); + if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) ) + _createdBy = new Exception("Created by"); } public I2PThread(String name) { super(name); + if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) ) + _createdBy = new Exception("Created by"); } public I2PThread(Runnable r) { super(r); + if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) ) + _createdBy = new Exception("Created by"); } public I2PThread(Runnable r, String 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() { + _name = Thread.currentThread().getName(); + log(Log.DEBUG, "New thread started: " + _name, _createdBy); try { super.run(); } catch (Throwable t) { try { - // we cant assume log is created - if (_log == null) _log = new Log(I2PThread.class); - _log.log(Log.CRIT, "Killing thread " + getName(), t); + log(Log.CRIT, "Killing thread " + getName(), t); } catch (Throwable woof) { System.err.println("Died within the OOM itself"); t.printStackTrace(); @@ -54,6 +72,12 @@ public class I2PThread extends Thread { if (t instanceof OutOfMemoryError) 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) { diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index 2459b715e8e3660cf8184e32aa02734d099aa738..bf267b657f5c77cc305e642e70b366a5424555bb 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -539,6 +539,7 @@ public class Router { public static final int EXIT_GRACEFUL = 2; public static final int EXIT_HARD = 3; public static final int EXIT_OOM = 10; + public static final int EXIT_HARD_RESTART = 4; public void shutdown(int exitCode) { _isAlive = false;