X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=unused%2Fsrcjar_unused%2Forg%2Fapache%2Flog4j%2FAsyncAppender.java;fp=unused%2Fsrcjar_unused%2Forg%2Fapache%2Flog4j%2FAsyncAppender.java;h=214ffa7b9b12e08bfbb864b360a8314351c83875;hb=7e01e1b3e9c8abdf952e085dba51e9266f12b1ee;hp=0000000000000000000000000000000000000000;hpb=88635c3965bb2f1f45e53c2d5f66fed19b93012a;p=jalview.git diff --git a/unused/srcjar_unused/org/apache/log4j/AsyncAppender.java b/unused/srcjar_unused/org/apache/log4j/AsyncAppender.java new file mode 100644 index 0000000..214ffa7 --- /dev/null +++ b/unused/srcjar_unused/org/apache/log4j/AsyncAppender.java @@ -0,0 +1,596 @@ +/* + * 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. + */ + +// Contibutors: Aaron Greenhouse +// Thomas Tuft Muller +package org.apache.log4j; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.helpers.AppenderAttachableImpl; +import org.apache.log4j.spi.AppenderAttachable; +import org.apache.log4j.spi.LoggingEvent; + + +/** + * The AsyncAppender lets users log events asynchronously. + *

+ *

+ * The AsyncAppender will collect the events sent to it and then dispatch them + * to all the appenders that are attached to it. You can attach multiple + * appenders to an AsyncAppender. + *

+ *

+ *

+ * The AsyncAppender uses a separate thread to serve the events in its buffer. + *

+ *

+ * Important note: The AsyncAppender can only be script + * configured using the {@link org.apache.log4j.xml.DOMConfigurator}. + *

+ * + * @author Ceki Gülcü + * @author Curt Arnold + * @since 0.9.1 + */ +public class AsyncAppender extends AppenderSkeleton + implements AppenderAttachable { + /** + * The default buffer size is set to 128 events. + */ + public static final int DEFAULT_BUFFER_SIZE = 128; + + /** + * Event buffer, also used as monitor to protect itself and + * discardMap from simulatenous modifications. + */ + private final List buffer = new ArrayList(); + + /** + * Map of DiscardSummary objects keyed by logger name. + */ + private final Map discardMap = new HashMap(); + + /** + * Buffer size. + */ + private int bufferSize = DEFAULT_BUFFER_SIZE; + + /** Nested appenders. */ + AppenderAttachableImpl aai; + + /** + * Nested appenders. + */ + private final AppenderAttachableImpl appenders; + + /** + * Dispatcher. + */ + private final Thread dispatcher; + + /** + * Should location info be included in dispatched messages. + */ + private boolean locationInfo = false; + + /** + * Does appender block when buffer is full. + */ + private boolean blocking = true; + + /** + * Create new instance. + */ + public AsyncAppender() { + appenders = new AppenderAttachableImpl(); + + // + // only set for compatibility + aai = appenders; + + dispatcher = + new Thread(new Dispatcher(this, buffer, discardMap, appenders)); + + // It is the user's responsibility to close appenders before + // exiting. + dispatcher.setDaemon(true); + + // set the dispatcher priority to lowest possible value + // dispatcher.setPriority(Thread.MIN_PRIORITY); + dispatcher.setName("AsyncAppender-Dispatcher-" + dispatcher.getName()); + dispatcher.start(); + } + + /** + * Add appender. + * + * @param newAppender appender to add, may not be null. + */ + public void addAppender(final Appender newAppender) { + synchronized (appenders) { + appenders.addAppender(newAppender); + } + } + + /** + * {@inheritDoc} + */ + public void append(final LoggingEvent event) { + // + // if dispatcher thread has died then + // append subsequent events synchronously + // See bug 23021 + if ((dispatcher == null) || !dispatcher.isAlive() || (bufferSize <= 0)) { + synchronized (appenders) { + appenders.appendLoopOnAppenders(event); + } + + return; + } + + // Set the NDC and thread name for the calling thread as these + // LoggingEvent fields were not set at event creation time. + event.getNDC(); + event.getThreadName(); + // Get a copy of this thread's MDC. + event.getMDCCopy(); + if (locationInfo) { + event.getLocationInformation(); + } + event.getRenderedMessage(); + event.getThrowableStrRep(); + + synchronized (buffer) { + while (true) { + int previousSize = buffer.size(); + + if (previousSize < bufferSize) { + buffer.add(event); + + // + // if buffer had been empty + // signal all threads waiting on buffer + // to check their conditions. + // + if (previousSize == 0) { + buffer.notifyAll(); + } + + break; + } + + // + // Following code is only reachable if buffer is full + // + // + // if blocking and thread is not already interrupted + // and not the dispatcher then + // wait for a buffer notification + boolean discard = true; + if (blocking + && !Thread.interrupted() + && Thread.currentThread() != dispatcher) { + try { + buffer.wait(); + discard = false; + } catch (InterruptedException e) { + // + // reset interrupt status so + // calling code can see interrupt on + // their next wait or sleep. + Thread.currentThread().interrupt(); + } + } + + // + // if blocking is false or thread has been interrupted + // add event to discard map. + // + if (discard) { + String loggerName = event.getLoggerName(); + DiscardSummary summary = (DiscardSummary) discardMap.get(loggerName); + + if (summary == null) { + summary = new DiscardSummary(event); + discardMap.put(loggerName, summary); + } else { + summary.add(event); + } + + break; + } + } + } + } + + /** + * Close this AsyncAppender by interrupting the dispatcher + * thread which will process all pending events before exiting. + */ + public void close() { + /** + * Set closed flag and notify all threads to check their conditions. + * Should result in dispatcher terminating. + */ + synchronized (buffer) { + closed = true; + buffer.notifyAll(); + } + + try { + dispatcher.join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + org.apache.log4j.helpers.LogLog.error( + "Got an InterruptedException while waiting for the " + + "dispatcher to finish.", e); + } + + // + // close all attached appenders. + // + synchronized (appenders) { + Enumeration iter = appenders.getAllAppenders(); + + if (iter != null) { + while (iter.hasMoreElements()) { + Object next = iter.nextElement(); + + if (next instanceof Appender) { + ((Appender) next).close(); + } + } + } + } + } + + /** + * Get iterator over attached appenders. + * @return iterator or null if no attached appenders. + */ + public Enumeration getAllAppenders() { + synchronized (appenders) { + return appenders.getAllAppenders(); + } + } + + /** + * Get appender by name. + * + * @param name name, may not be null. + * @return matching appender or null. + */ + public Appender getAppender(final String name) { + synchronized (appenders) { + return appenders.getAppender(name); + } + } + + /** + * Gets whether the location of the logging request call + * should be captured. + * + * @return the current value of the LocationInfo option. + */ + public boolean getLocationInfo() { + return locationInfo; + } + + /** + * Determines if specified appender is attached. + * @param appender appender. + * @return true if attached. + */ + public boolean isAttached(final Appender appender) { + synchronized (appenders) { + return appenders.isAttached(appender); + } + } + + /** + * {@inheritDoc} + */ + public boolean requiresLayout() { + return false; + } + + /** + * Removes and closes all attached appenders. + */ + public void removeAllAppenders() { + synchronized (appenders) { + appenders.removeAllAppenders(); + } + } + + /** + * Removes an appender. + * @param appender appender to remove. + */ + public void removeAppender(final Appender appender) { + synchronized (appenders) { + appenders.removeAppender(appender); + } + } + + /** + * Remove appender by name. + * @param name name. + */ + public void removeAppender(final String name) { + synchronized (appenders) { + appenders.removeAppender(name); + } + } + + /** + * The LocationInfo option takes a boolean value. By default, it is + * set to false which means there will be no effort to extract the location + * information related to the event. As a result, the event that will be + * ultimately logged will likely to contain the wrong location information + * (if present in the log format). + *

+ *

+ * Location information extraction is comparatively very slow and should be + * avoided unless performance is not a concern. + *

+ * @param flag true if location information should be extracted. + */ + public void setLocationInfo(final boolean flag) { + locationInfo = flag; + } + + /** + * Sets the number of messages allowed in the event buffer + * before the calling thread is blocked (if blocking is true) + * or until messages are summarized and discarded. Changing + * the size will not affect messages already in the buffer. + * + * @param size buffer size, must be positive. + */ + public void setBufferSize(final int size) { + // + // log4j 1.2 would throw exception if size was negative + // and deadlock if size was zero. + // + if (size < 0) { + throw new java.lang.NegativeArraySizeException("size"); + } + + synchronized (buffer) { + // + // don't let size be zero. + // + bufferSize = (size < 1) ? 1 : size; + buffer.notifyAll(); + } + } + + /** + * Gets the current buffer size. + * @return the current value of the BufferSize option. + */ + public int getBufferSize() { + return bufferSize; + } + + /** + * Sets whether appender should wait if there is no + * space available in the event buffer or immediately return. + * + * @since 1.2.14 + * @param value true if appender should wait until available space in buffer. + */ + public void setBlocking(final boolean value) { + synchronized (buffer) { + blocking = value; + buffer.notifyAll(); + } + } + + /** + * Gets whether appender should block calling thread when buffer is full. + * If false, messages will be counted by logger and a summary + * message appended after the contents of the buffer have been appended. + * + * @since 1.2.14 + * @return true if calling thread will be blocked when buffer is full. + */ + public boolean getBlocking() { + return blocking; + } + + /** + * Summary of discarded logging events for a logger. + */ + private static final class DiscardSummary { + /** + * First event of the highest severity. + */ + private LoggingEvent maxEvent; + + /** + * Total count of messages discarded. + */ + private int count; + + /** + * Create new instance. + * + * @param event event, may not be null. + */ + public DiscardSummary(final LoggingEvent event) { + maxEvent = event; + count = 1; + } + + /** + * Add discarded event to summary. + * + * @param event event, may not be null. + */ + public void add(final LoggingEvent event) { + if (event.getLevel().toInt() > maxEvent.getLevel().toInt()) { + maxEvent = event; + } + + count++; + } + + /** + * Create event with summary information. + * + * @return new event. + */ + public LoggingEvent createEvent() { + String msg = + MessageFormat.format( + "Discarded {0} messages due to full event buffer including: {1}", + new Object[] { new Integer(count), maxEvent.getMessage() }); + + return new LoggingEvent( + "org.apache.log4j.AsyncAppender.DONT_REPORT_LOCATION", + Logger.getLogger(maxEvent.getLoggerName()), + maxEvent.getLevel(), + msg, + null); + } + } + + /** + * Event dispatcher. + */ + private static class Dispatcher implements Runnable { + /** + * Parent AsyncAppender. + */ + private final AsyncAppender parent; + + /** + * Event buffer. + */ + private final List buffer; + + /** + * Map of DiscardSummary keyed by logger name. + */ + private final Map discardMap; + + /** + * Wrapped appenders. + */ + private final AppenderAttachableImpl appenders; + + /** + * Create new instance of dispatcher. + * + * @param parent parent AsyncAppender, may not be null. + * @param buffer event buffer, may not be null. + * @param discardMap discard map, may not be null. + * @param appenders appenders, may not be null. + */ + public Dispatcher( + final AsyncAppender parent, final List buffer, final Map discardMap, + final AppenderAttachableImpl appenders) { + + this.parent = parent; + this.buffer = buffer; + this.appenders = appenders; + this.discardMap = discardMap; + } + + /** + * {@inheritDoc} + */ + public void run() { + boolean isActive = true; + + // + // if interrupted (unlikely), end thread + // + try { + // + // loop until the AsyncAppender is closed. + // + while (isActive) { + LoggingEvent[] events = null; + + // + // extract pending events while synchronized + // on buffer + // + synchronized (buffer) { + int bufferSize = buffer.size(); + isActive = !parent.closed; + + while ((bufferSize == 0) && isActive) { + buffer.wait(); + bufferSize = buffer.size(); + isActive = !parent.closed; + } + + if (bufferSize > 0) { + events = new LoggingEvent[bufferSize + discardMap.size()]; + buffer.toArray(events); + + // + // add events due to buffer overflow + // + int index = bufferSize; + + for ( + Iterator iter = discardMap.values().iterator(); + iter.hasNext();) { + events[index++] = ((DiscardSummary) iter.next()).createEvent(); + } + + // + // clear buffer and discard map + // + buffer.clear(); + discardMap.clear(); + + // + // allow blocked appends to continue + buffer.notifyAll(); + } + } + + // + // process events after lock on buffer is released. + // + if (events != null) { + for (int i = 0; i < events.length; i++) { + synchronized (appenders) { + appenders.appendLoopOnAppenders(events[i]); + } + } + } + } + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } +}