On 29/10/2008, [EMAIL PROTECTED] <[EMAIL PROTECTED]> wrote: > Author: fhanik > Date: Wed Oct 29 14:41:09 2008 > New Revision: 709018 > > URL: http://svn.apache.org/viewvc?rev=709018&view=rev > Log: > Add asynchronous log handling, feature not yet complete. Need to figure out > when to stop the logger thread (possible when there are no loggers) and also > make sure the thread sleep/wakeup is bullet proof > > > Added: > tomcat/trunk/java/org/apache/juli/AsyncFileHandler.java > Modified: > tomcat/trunk/java/org/apache/juli/FileHandler.java > > Added: tomcat/trunk/java/org/apache/juli/AsyncFileHandler.java > URL: > http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/juli/AsyncFileHandler.java?rev=709018&view=auto > > ============================================================================== > --- tomcat/trunk/java/org/apache/juli/AsyncFileHandler.java (added) > +++ tomcat/trunk/java/org/apache/juli/AsyncFileHandler.java Wed Oct 29 > 14:41:09 2008 > @@ -0,0 +1,217 @@ > +/* > + * Licensed to the Apache Software Foundation (ASF) under one or more > + * contributor license agreements. See the NOTICE file distributed with > + * this work for additional information regarding copyright ownership. > + * The ASF licenses this file to You under the Apache License, Version 2.0 > + * (the "License"); you may not use this file except in compliance with > + * the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > +package org.apache.juli; > + > +import java.util.concurrent.ConcurrentLinkedQueue; > +import java.util.concurrent.atomic.AtomicLong; > +import java.util.concurrent.locks.Condition; > +import java.util.concurrent.locks.ReentrantLock; > +import java.util.logging.LogRecord; > +/** > + * > + * @author Filip Hanik > + * > + */ > +public class AsyncFileHandler extends FileHandler { > + > + public static final int OVERFLOW_DROP_LAST = 1; > + public static final int OVERFLOW_DROP_FIRST = 2; > + public static final int DEFAULT_MAX_RECORDS = 1000; > + public static final int RECORD_BATCH_COUNT = > Integer.parseInt(System.getProperty("org.apache.juli.AsyncRecordBatchCount","100")); > + > + protected static ConcurrentLinkedQueue<FileHandler> handlers = new > ConcurrentLinkedQueue<FileHandler>(); > + protected static SignalAtomicLong recordCounter = new > SignalAtomicLong(); > + protected static LoggerThread logger = new LoggerThread(); > +
It would be safer to make the above final, if possible. If not possible, then there are probably thread-safety issues. > + static { > + logger.start(); > + } > + > + protected LogQueue<LogRecord> queue = new LogQueue<LogRecord>(); Ditto. > + protected boolean closed = false; Probably needs to be volatile - else all accesses need to be sych. > + > + public AsyncFileHandler() { > + this(null,null,null); > + } > + > + public AsyncFileHandler(String directory, String prefix, String suffix) > { > + super(directory, prefix, suffix); > + open(); > + } > + > + @Override > + public void close() { > + closed = true; > + // TODO Auto-generated method stub > + super.close(); > + handlers.remove(this); > + } > + > + @Override > + protected void open() { > + closed = false; > + // TODO Auto-generated method stub > + super.open(); > + handlers.add(this); > + } > + > + > + @Override > + public void publish(LogRecord record) { > + if (!isLoggable(record)) { > + return; > + } > + this.queue.offer(record); > + } > + > + protected void publishInternal(LogRecord record) { > + recordCounter.addAndGet(-1); > + super.publish(record); > + } > + > + @Override > + protected void finalize() throws Throwable { > + // TODO Auto-generated method stub > + super.finalize(); > + } > + > + public int getMaxRecords() { > + return this.queue.max; > + } > + > + public void setMaxRecords(int maxRecords) { > + this.queue.max = maxRecords; > + } > + > + public int getOverflowAction() { > + return this.queue.type; > + } > + > + public void setOverflowAction(int type) { > + this.queue.type = type; > + } > + > + protected static class SignalAtomicLong { > + AtomicLong delegate = new AtomicLong(0); > + ReentrantLock lock = new ReentrantLock(); > + Condition cond = lock.newCondition(); > + > + public long addAndGet(long i) { > + long prevValue = delegate.getAndAdd(i); > + if (prevValue<=0 && i>0) { > + lock.lock(); > + try { > + cond.signalAll(); > + } finally { > + lock.unlock(); > + } > + } > + return delegate.get(); > + } > + > + public void sleepUntilPositive() throws InterruptedException { > + if (delegate.get()>0) return; > + lock.lock(); > + try { > + if (delegate.get()>0) return; > + cond.await(); > + } finally { > + lock.unlock(); > + } > + } > + > + public long get() { > + return delegate.get(); > + } > + > + } > + > + protected static class LoggerThread extends Thread { > + protected boolean run = true; Needs to be volatile, as it is used by at least 2 threads. > + public LoggerThread() { > + this.setDaemon(true); > + > this.setName("AsyncFileHandlerWriter-"+System.identityHashCode(this)); > + } > + > + public void run() { > + while (run) { > + try { > + AsyncFileHandler.recordCounter.sleepUntilPositive(); > + } catch (InterruptedException x) { > + this.interrupted(); > + continue; > + } > + AsyncFileHandler[] handlers = > AsyncFileHandler.handlers.toArray(new AsyncFileHandler[0]); > + for (int i=0; run && i<handlers.length; i++) { > + int counter = 0; > + while (run && (counter++)<RECORD_BATCH_COUNT) { > + if (handlers[i].closed) break; > + LogRecord record = handlers[i].queue.poll(); > + if (record==null) break; > + handlers[i].publishInternal(record); > + }//while > + }//for > + }//while > + } > + } > + > + protected static class LogQueue<E> { > + protected int max = DEFAULT_MAX_RECORDS; > + protected int type = OVERFLOW_DROP_LAST; > + protected ConcurrentLinkedQueue<E> delegate = new > ConcurrentLinkedQueue<E>(); Can these be final? > + > + public boolean offer(E e) { > + if (delegate.size()>=max) { > + switch (type) { > + case OVERFLOW_DROP_LAST: > + return false; > + case OVERFLOW_DROP_FIRST: { > + this.poll(); > + if (delegate.offer(e)) { > + recordCounter.addAndGet(1); > + return true; > + } else { > + return false; > + } > + } > + default: > + return false; > + } > + } else { > + if (delegate.offer(e)) { > + recordCounter.addAndGet(1); > + return true; > + } else { > + return false; > + } > + > + } > + } > + > + public E peek() { > + return delegate.peek(); > + } > + > + public E poll() { > + // TODO Auto-generated method stub > + return delegate.poll(); > + } > + > + } > + > + > +} > > Modified: tomcat/trunk/java/org/apache/juli/FileHandler.java > URL: > http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/juli/FileHandler.java?rev=709018&r1=709017&r2=709018&view=diff > > ============================================================================== > --- tomcat/trunk/java/org/apache/juli/FileHandler.java (original) > +++ tomcat/trunk/java/org/apache/juli/FileHandler.java Wed Oct 29 14:41:09 > 2008 > @@ -56,7 +56,7 @@ > this.prefix = prefix; > this.suffix = suffix; > configure(); > - open(); > + openWriter(); > } > > > @@ -117,9 +117,9 @@ > if (!date.equals(tsDate)) { > synchronized (this) { > if (!date.equals(tsDate)) { > - close(); > + closeWriter(); > date = tsDate; > - open(); > + openWriter(); > } > } > } > @@ -154,6 +154,10 @@ > * Close the currently open log file (if any). > */ > public void close() { > + closeWriter(); > + } > + > + protected void closeWriter() { > > try { > if (writer == null) > @@ -193,7 +197,7 @@ > String tsString = ts.toString().substring(0, 19); > date = tsString.substring(0, 10); > > - String className = FileHandler.class.getName(); > + String className = this.getClass().getName(); //allow classes to > override > > ClassLoader cl = Thread.currentThread().getContextClassLoader(); > > @@ -250,7 +254,11 @@ > /** > * Open the new log file for the date specified by <code>date</code>. > */ > - private void open() { > + protected void open() { > + openWriter(); > + } > + > + protected void openWriter() { > > // Create the directory if necessary > File dir = new File(directory); > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > > --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]