* 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:
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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>";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
Reference in New Issue
Block a user