Logger now uses only one Thread for all instances.

Instead of a Vector, a Linked List is used as log buffer,
which is much better for removing items at the top
of the list.
This commit is contained in:
hns 2001-08-31 15:44:50 +00:00
parent a3074265e4
commit 0b35d05b2b

View file

@ -11,11 +11,14 @@ import java.text.*;
* Utility class for asynchronous logging.
*/
public class Logger implements Runnable {
public final class Logger {
private Thread logger;
// we use one static thread for all Loggers
static Runner runner;
// the list of active loggers
static ArrayList loggers;
private Vector entries;
private LinkedList entries;
private String filename;
private String dirname;
private File dir;
@ -27,23 +30,31 @@ public class Logger implements Runnable {
private long dateLastRendered;
private String dateCache;
private PrintStream out = null;
boolean closed = false;
/**
* Create a logger for a PrintStream, such as System.out.
*/
public Logger (PrintStream out) {
dformat = DateFormat.getInstance ();
dformat = new SimpleDateFormat ("[yyyy/MM/dd HH:mm] ");
this.out = out;
entries = new Vector ();
logger = new Thread (this);
// logger.setPriority (Thread.MIN_PRIORITY+2);
logger.start ();
entries = new LinkedList ();
// register this instance with static logger list
start (this);
}
/**
* Create a file logger. The actual file names do have numbers appended and are
* rotated every x bytes.
*/
public Logger (String dirname, String filename) throws IOException {
if (filename == null || dirname == null)
throw new IOException ("Logger can't use null as file or directory name");
this.filename = filename;
this.dirname = dirname;
nformat = new DecimalFormat ("00000");
dformat = DateFormat.getInstance ();
dformat = new SimpleDateFormat ("[yyyy/MM/dd HH:mm] ");
dir = new File (dirname);
if (!dir.exists())
dir.mkdirs ();
@ -51,17 +62,20 @@ public class Logger implements Runnable {
while (currentFile.exists())
currentFile = new File (dir, filename+nformat.format(++fileindex)+".log");
currentWriter = new PrintWriter (new FileWriter (currentFile), false);
entries = new Vector ();
logger = new Thread (this);
// logger.setPriority (Thread.MIN_PRIORITY+2);
logger.start ();
entries = new LinkedList ();
// register this instance with static logger list
start (this);
}
/**
* Append a message with to the log.
*/
public void log (String msg) {
// it's enough to render the date every 15 seconds
if (System.currentTimeMillis () - 15000 > dateLastRendered)
renderDate ();
entries.addElement (dateCache + " " + msg);
entries.add (dateCache + msg);
}
private synchronized void renderDate () {
@ -69,34 +83,42 @@ public class Logger implements Runnable {
dateCache = dformat.format (new Date());
}
/**
* This is called by the runner thread to perform actual IO.
*/
public void run () {
while (Thread.currentThread () == logger) {
try {
if (currentFile != null && currentFile.length() > 10000000) {
// rotate log files each 10 megs
swapFile ();
}
int l = entries.size();
for (int i=0; i<l; i++) {
Object entry = entries.elementAt (0);
entries.removeElementAt (0);
if (out != null)
out.println (entry.toString());
else
currentWriter.println (entry.toString());
}
if (currentWriter != null)
currentWriter.flush ();
logger.sleep (1000l);
} catch (InterruptedException ir) {
Thread.currentThread().interrupt ();
if (entries.isEmpty ())
return;
try {
if (currentFile != null && currentFile.length() > 10000000) {
// rotate log files each 10 megs
swapFile ();
}
int l = entries.size();
if (out != null) {
for (int i=0; i<l; i++) {
String entry = (String) entries.get (0);
entries.remove (0);
out.println (entry);
}
} else {
for (int i=0; i<l; i++) {
String entry = (String) entries.get (0);
entries.remove (0);
currentWriter.println (entry);
}
currentWriter.flush ();
}
} catch (Exception x) {
//
}
}
/**
* Rotata log files, closing the old file and starting a new one.
*/
private void swapFile () {
try {
currentWriter.close();
@ -107,4 +129,74 @@ public class Logger implements Runnable {
}
}
/**
* The static start class adds a log to the list of logs and starts the
* runner thread if necessary.
*/
static synchronized void start (Logger log) {
if (loggers == null) {
loggers = new ArrayList ();
}
loggers.add (log);
if (runner == null || !runner.isAlive ()) {
runner = new Runner ();
runner.setPriority (Thread.NORM_PRIORITY-1);
runner.start ();
}
}
/**
* Tells a log to close down
*/
public void close () {
this.closed = true;
}
/**
* Closes the file writer of a log
*/
void closeFiles () {
if (currentWriter != null) try {
currentWriter.close ();
} catch (Exception ignore) {}
}
/**
* The static runner class that loops through all loggers.
*/
static class Runner extends Thread {
public void run () {
while (!isInterrupted ()) {
int l = loggers.size();
for (int i=l-1; i>=0; i--) {
Logger log = (Logger) loggers.get (i);
log.run ();
if (log.closed) {
loggers.remove (log);
log.closeFiles ();
}
}
try {
sleep (700);
} catch (InterruptedException ix) {}
}
}
}
/**
* test main method
*/
public static void main (String[] args) throws IOException {
Logger log = new Logger (".", "testlog");
long start = System.currentTimeMillis ();
for (int i=0; i<50000; i++)
log.log ("test log entry aasdfasdfasdfasdf");
log.log ("done: "+(System.currentTimeMillis () - start));
System.err.println (System.currentTimeMillis () - start);
System.exit (0);
}
}