* 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:
zzz
2010-11-30 15:07:45 +00:00
parent 9147fddb8e
commit 45b8d8b6b5
3 changed files with 44 additions and 19 deletions

View File

@ -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) {
log(DEBUG, msg);
}

View File

@ -23,6 +23,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeMap;
@ -78,6 +79,9 @@ public class LogManager {
/** the config file */
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 */
private final LinkedBlockingQueue<LogRecord> _records;
/** List of explicit overrides of log levels (LogLimit objects) */
@ -119,7 +123,7 @@ public class LogManager {
public LogManager(I2PAppContext context) {
_displayOnScreen = true;
_alreadyNoticedMissingConfig = false;
_records = new LinkedBlockingQueue();
_records = new LinkedBlockingQueue(MAX_BUFFER);
_limits = new ConcurrentHashSet();
_logs = new ConcurrentHashMap(128);
_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) {
if ((!_context.isRouterContext()) && _writer == null)
startLogWriter();
_records.offer(record);
/**** don't burden the logging thread with counting
int numRecords = _records.size();
if (numRecords > 100) {
boolean success = _records.offer(record);
if (!success) {
// the writer waits 10 seconds *or* until we tell them to wake up
// before rereading the config and writing out any log messages
synchronized (_writer) {
_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();
}
List<LogRecord> _removeAll() {
List<LogRecord> vals = new LinkedList();
_records.drainTo(vals);
return vals;
/**
* Zero-copy.
* For the LogWriter
* @since 0.8.2
*/
Queue<LogRecord> getQueue() {
return _records;
}
public char[] getFormat() {

View File

@ -15,7 +15,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.List;
import java.util.Queue;
import net.i2p.I2PAppContext;
@ -38,6 +38,8 @@ class LogWriter implements Runnable {
private LogManager _manager;
private boolean _write;
private static final int MAX_DISKFULL_MESSAGES = 8;
private int _diskFullMessageCount;
private LogWriter() { // nop
}
@ -61,7 +63,7 @@ class LogWriter implements Runnable {
}
//System.err.println("Done writing");
} catch (Exception e) {
System.err.println("Error writing the logs: " + e.getMessage());
System.err.println("Error writing the log: " + e);
e.printStackTrace();
}
closeFile();
@ -70,16 +72,19 @@ class LogWriter implements Runnable {
public void flushRecords() { flushRecords(true); }
public void flushRecords(boolean shouldWait) {
try {
List<LogRecord> records = _manager._removeAll();
// zero copy, drain the manager queue directly
Queue<LogRecord> records = _manager.getQueue();
if (records == null) return;
if (!records.isEmpty()) {
for (LogRecord rec : records) {
LogRecord rec;
while ((rec = records.poll()) != null) {
writeRecord(rec);
}
try {
_currentOut.flush();
} 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) {
@ -138,6 +143,7 @@ class LogWriter implements Runnable {
} catch (Throwable t) {
if (!_write)
return;
if (++_diskFullMessageCount < MAX_DISKFULL_MESSAGES)
System.err.println("Error writing log, disk full? " + t);
//t.printStackTrace();
}