* Logging:
- Limit buffer size; block and wakeup writer when full - Limit errors written to system log - Add method to force a log below the current level
This commit is contained in:
@ -117,6 +117,17 @@ public class Log {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Always log this messge with the given priority, ignoring current minimum priority level.
|
||||||
|
* This allows an INFO message about changing port numbers, for example, to always be logged.
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
public void logAlways(int priority, String msg) {
|
||||||
|
_manager.addRecord(new LogRecord(_class, _name,
|
||||||
|
Thread.currentThread().getName(), priority,
|
||||||
|
msg, null));
|
||||||
|
}
|
||||||
|
|
||||||
public void debug(String msg) {
|
public void debug(String msg) {
|
||||||
log(DEBUG, msg);
|
log(DEBUG, msg);
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.Queue;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
@ -78,6 +79,9 @@ public class LogManager {
|
|||||||
|
|
||||||
/** the config file */
|
/** the config file */
|
||||||
private File _locationFile;
|
private File _locationFile;
|
||||||
|
|
||||||
|
/** max to LogRecords to buffer in memory before we start blocking */
|
||||||
|
private static final int MAX_BUFFER = 1024;
|
||||||
/** Ordered list of LogRecord elements that have not been written out yet */
|
/** Ordered list of LogRecord elements that have not been written out yet */
|
||||||
private final LinkedBlockingQueue<LogRecord> _records;
|
private final LinkedBlockingQueue<LogRecord> _records;
|
||||||
/** List of explicit overrides of log levels (LogLimit objects) */
|
/** List of explicit overrides of log levels (LogLimit objects) */
|
||||||
@ -119,7 +123,7 @@ public class LogManager {
|
|||||||
public LogManager(I2PAppContext context) {
|
public LogManager(I2PAppContext context) {
|
||||||
_displayOnScreen = true;
|
_displayOnScreen = true;
|
||||||
_alreadyNoticedMissingConfig = false;
|
_alreadyNoticedMissingConfig = false;
|
||||||
_records = new LinkedBlockingQueue();
|
_records = new LinkedBlockingQueue(MAX_BUFFER);
|
||||||
_limits = new ConcurrentHashSet();
|
_limits = new ConcurrentHashSet();
|
||||||
_logs = new ConcurrentHashMap(128);
|
_logs = new ConcurrentHashMap(128);
|
||||||
_defaultLimit = Log.ERROR;
|
_defaultLimit = Log.ERROR;
|
||||||
@ -221,25 +225,26 @@ public class LogManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by Log to add records to the queue
|
* Used by Log to add records to the queue.
|
||||||
*
|
* This is generally nonblocking and unsyncrhonized but may block when under
|
||||||
|
* massive logging load as a way of throttling logging threads.
|
||||||
*/
|
*/
|
||||||
void addRecord(LogRecord record) {
|
void addRecord(LogRecord record) {
|
||||||
if ((!_context.isRouterContext()) && _writer == null)
|
if ((!_context.isRouterContext()) && _writer == null)
|
||||||
startLogWriter();
|
startLogWriter();
|
||||||
|
|
||||||
_records.offer(record);
|
boolean success = _records.offer(record);
|
||||||
/**** don't burden the logging thread with counting
|
if (!success) {
|
||||||
int numRecords = _records.size();
|
|
||||||
|
|
||||||
if (numRecords > 100) {
|
|
||||||
// the writer waits 10 seconds *or* until we tell them to wake up
|
// the writer waits 10 seconds *or* until we tell them to wake up
|
||||||
// before rereading the config and writing out any log messages
|
// before rereading the config and writing out any log messages
|
||||||
synchronized (_writer) {
|
synchronized (_writer) {
|
||||||
_writer.notifyAll();
|
_writer.notifyAll();
|
||||||
}
|
}
|
||||||
|
// block as a way of slowing down out-of-control loggers (a little)
|
||||||
|
try {
|
||||||
|
_records.put(record);
|
||||||
|
} catch (InterruptedException ie) {}
|
||||||
}
|
}
|
||||||
****/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -605,10 +610,13 @@ public class LogManager {
|
|||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<LogRecord> _removeAll() {
|
/**
|
||||||
List<LogRecord> vals = new LinkedList();
|
* Zero-copy.
|
||||||
_records.drainTo(vals);
|
* For the LogWriter
|
||||||
return vals;
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
Queue<LogRecord> getQueue() {
|
||||||
|
return _records;
|
||||||
}
|
}
|
||||||
|
|
||||||
public char[] getFormat() {
|
public char[] getFormat() {
|
||||||
|
@ -15,7 +15,7 @@ import java.io.IOException;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.List;
|
import java.util.Queue;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
|
|
||||||
@ -38,6 +38,8 @@ class LogWriter implements Runnable {
|
|||||||
private LogManager _manager;
|
private LogManager _manager;
|
||||||
|
|
||||||
private boolean _write;
|
private boolean _write;
|
||||||
|
private static final int MAX_DISKFULL_MESSAGES = 8;
|
||||||
|
private int _diskFullMessageCount;
|
||||||
|
|
||||||
private LogWriter() { // nop
|
private LogWriter() { // nop
|
||||||
}
|
}
|
||||||
@ -61,7 +63,7 @@ class LogWriter implements Runnable {
|
|||||||
}
|
}
|
||||||
//System.err.println("Done writing");
|
//System.err.println("Done writing");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println("Error writing the logs: " + e.getMessage());
|
System.err.println("Error writing the log: " + e);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
closeFile();
|
closeFile();
|
||||||
@ -70,16 +72,19 @@ class LogWriter implements Runnable {
|
|||||||
public void flushRecords() { flushRecords(true); }
|
public void flushRecords() { flushRecords(true); }
|
||||||
public void flushRecords(boolean shouldWait) {
|
public void flushRecords(boolean shouldWait) {
|
||||||
try {
|
try {
|
||||||
List<LogRecord> records = _manager._removeAll();
|
// zero copy, drain the manager queue directly
|
||||||
|
Queue<LogRecord> records = _manager.getQueue();
|
||||||
if (records == null) return;
|
if (records == null) return;
|
||||||
if (!records.isEmpty()) {
|
if (!records.isEmpty()) {
|
||||||
for (LogRecord rec : records) {
|
LogRecord rec;
|
||||||
|
while ((rec = records.poll()) != null) {
|
||||||
writeRecord(rec);
|
writeRecord(rec);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
_currentOut.flush();
|
_currentOut.flush();
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
System.err.println("Error writing the router log");
|
if (++_diskFullMessageCount < MAX_DISKFULL_MESSAGES)
|
||||||
|
System.err.println("Error writing the router log - disk full? " + ioe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
@ -138,6 +143,7 @@ class LogWriter implements Runnable {
|
|||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
if (!_write)
|
if (!_write)
|
||||||
return;
|
return;
|
||||||
|
if (++_diskFullMessageCount < MAX_DISKFULL_MESSAGES)
|
||||||
System.err.println("Error writing log, disk full? " + t);
|
System.err.println("Error writing log, disk full? " + t);
|
||||||
//t.printStackTrace();
|
//t.printStackTrace();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user