The version of Apache log4j used by SoundHelix.
Clone
HTTPS:
git clone https://vervis.peers.community/repos/aEp6o
SSH:
git clone USERNAME@vervis.peers.community:aEp6o
Branches
Tags
- 1.3alpha-7
- CHAINSAW_2_SANDBOX_MERGE
- CORE_VERSION
- LEVEL_REPLACES_PRIORITY
- PREALPHA_1_3_AS_OF_2004_05_12
- PRE_CHAINSAW_MODEL_CONVERSION
- PRE_UGLI_MOVE
- TAG_CHAINSAW2_MOVE
- log4j-1.2.17
- log4j-1.2.17-rc1
- v1.3alpha8
- v1.3alpha8-temp
- v1_2_1
- v1_2_10-recalled
- v1_2_11
- v1_2_11_rc1
- v1_2_11rc3
- v1_2_12
- v1_2_12_rc1
- v1_2_12_rc2
- v1_2_12_rc3
- v1_2_12_rc4
- v1_2_12_rc5
- v1_2_12_rc6
- v1_2_13
- v1_2_13_rc1
- v1_2_13_rc2
- v1_2_13_site_update
- v1_2_14
- v1_2_14_maven
- v1_2_14_rc1
- v1_2_14_site_update
- v1_2_15
- v1_2_15_rc1
- v1_2_15_rc2
- v1_2_15_rc3
- v1_2_15_rc4
- v1_2_15_rc5
- v1_2_15_rc6
- v1_2_16
- v1_2_16_rc1
- v1_2_16_rc2
- v1_2_17
- v1_2_17-rc1
- v1_2_17_rc1
- v1_2_17_rc2
- v1_2_17_rc3
- v1_2_2
- v1_2_3
- v1_2_4
- v1_2_6
- v1_2_7
- v1_2_9
- v1_2_alpha0
- v1_2_alpha7
- v1_2beta1
- v1_2final
- v1_3alpha_1
- v1_3alpha_6
- v_1_0
- v_1_0_1
- v_1_0_4
- v_1_1
- v_1_1_1
- v_1_1_2
- v_1_1_3
- v_1_1_b1
- v_1_1b2
- v_1_1b3
- v_1_1b5
- v_1_1b6
- v_1_1b7
- v_1_2beta3
AsyncAppender.java
/*
* Copyright 1999,2004 The Apache Software Foundation.
*
* Licensed 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 <aarong@cs.cmu.edu>
// Thomas Tuft Muller <ttm@online.no>
package org.apache.log4j;
import org.apache.log4j.helpers.AppenderAttachableImpl;
import org.apache.log4j.helpers.BoundedFIFO;
import org.apache.log4j.spi.AppenderAttachable;
import org.apache.log4j.spi.LoggingEvent;
import java.util.Enumeration;
/**
* The AsyncAppender lets users log events asynchronously. It uses a bounded
* buffer to store logging events.
*
* <p>
* 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.
* </p>
*
* <p>
* The AsyncAppender uses a separate thread to serve the events in its bounded
* buffer.
* </p>
* * <p>
* <b>Important note:</b> The <code>AsyncAppender</code> can only be script
* configured using the {@link org.apache.log4j.joran.JoranConfigurator}.
* </p>
*
* @author Ceki Gülcü
*
* @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;
//static Category cat = Category.getInstance(AsyncAppender.class.getName());
private BoundedFIFO bf = new BoundedFIFO(DEFAULT_BUFFER_SIZE);
AppenderAttachableImpl aai;
private Dispatcher dispatcher;
private boolean locationInfo = false;
private boolean interruptedWarningMessage = false;
public AsyncAppender() {
super(true);
// Note: The dispatcher code assumes that the aai is set once and
// for all.
aai = new AppenderAttachableImpl();
dispatcher = new Dispatcher(bf, this);
dispatcher.start();
}
public void addAppender(Appender newAppender) {
synchronized (aai) {
aai.addAppender(newAppender);
}
}
public void append(LoggingEvent event) {
//
// if dispatcher thread has died then
// append subsequent events synchronously
// See bug 23021
if (!dispatcher.isAlive()) {
synchronized(aai) {
aai.appendLoopOnAppenders(event);
}
return;
}
// extract all the thread dependent information now as later it will
// be too late.
event.prepareForDeferredProcessing();
if (locationInfo) {
event.getLocationInformation();
}
synchronized (bf) {
while (bf.isFull()) {
try {
//LogLog.debug("Waiting for free space in buffer, "+bf.length());
bf.wait();
} catch (InterruptedException e) {
if (!interruptedWarningMessage) {
interruptedWarningMessage = true;
getLogger().warn("AsyncAppender interrupted.", e);
} else {
getLogger().warn("AsyncAppender interrupted again.");
}
}
}
//cat.debug("About to put new event in buffer.");
bf.put(event);
if (bf.wasEmpty()) {
//cat.debug("Notifying dispatcher to process events.");
bf.notify();
}
}
}
/**
* Close this <code>AsyncAppender</code> by interrupting the dispatcher
* thread which will process all pending events before exiting.
*/
public void close() {
synchronized (this) {
// avoid multiple close, otherwise one gets NullPointerException
if (closed) {
return;
}
closed = true;
}
// The following cannot be synchronized on "this" because the
// dispatcher synchronizes with "this" in its while loop. If we
// did synchronize we would systematically get deadlocks when
// close was called.
dispatcher.close();
try {
dispatcher.join();
} catch (InterruptedException e) {
getLogger().error(
"Got an InterruptedException while waiting for the "
+ "dispatcher to finish.", e);
}
dispatcher = null;
bf = null;
}
public Enumeration getAllAppenders() {
synchronized (aai) {
return aai.getAllAppenders();
}
}
public Appender getAppender(String name) {
synchronized (aai) {
return aai.getAppender(name);
}
}
/**
* Returns the current value of the <b>LocationInfo</b> option.
*/
public boolean getLocationInfo() {
return locationInfo;
}
/**
* Is the appender passed as parameter attached to this category?
*/
public boolean isAttached(Appender appender) {
return aai.isAttached(appender);
}
/**
* @deprecated Will be removed with no replacement.
*/
public boolean requiresLayout() {
return false;
}
public void removeAllAppenders() {
synchronized (aai) {
aai.removeAllAppenders();
}
}
public void removeAppender(Appender appender) {
synchronized (aai) {
aai.removeAppender(appender);
}
}
public void removeAppender(String name) {
synchronized (aai) {
aai.removeAppender(name);
}
}
/**
* The <b>LocationInfo</b> 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).
*
* <p>
* Location information extraction is comparatively very slow and should be
* avoided unless performance is not a concern.
* </p>
*/
public void setLocationInfo(boolean flag) {
locationInfo = flag;
}
/**
* The <b>BufferSize</b> option takes a non-negative integer value. This
* integer value determines the maximum size of the bounded buffer.
* Increasing the size of the buffer is always safe. However, if an
* existing buffer holds unwritten elements, then <em>decreasing the buffer
* size will result in event loss.</em> Nevertheless, while script
* configuring the AsyncAppender, it is safe to set a buffer size smaller
* than the {@link #DEFAULT_BUFFER_SIZE default buffer size} because
* configurators guarantee that an appender cannot be used before being
* completely configured.
*/
public void setBufferSize(int size) {
bf.resize(size);
}
/**
* Returns the current value of the <b>BufferSize</b> option.
*/
public int getBufferSize() {
// Bugzilla 23912
synchronized(bf) {
return bf.getMaxSize();
}
}
}
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// ----------------------------------------------------------------------------
class Dispatcher extends Thread {
private BoundedFIFO bf;
private AppenderAttachableImpl aai;
private boolean interrupted = false;
AsyncAppender container;
Dispatcher(BoundedFIFO bf, AsyncAppender container) {
this.bf = bf;
this.container = container;
this.aai = container.aai;
// It is the user's responsibility to close appenders before
// exiting.
this.setDaemon(true);
// set the dispatcher priority to lowest possible value
this.setPriority(Thread.MIN_PRIORITY);
this.setName("Dispatcher-" + getName());
// set the dispatcher priority to MIN_PRIORITY plus or minus 2
// depending on the direction of MIN to MAX_PRIORITY.
//+ (Thread.MAX_PRIORITY > Thread.MIN_PRIORITY ? 1 : -1)*2);
}
void close() {
synchronized (bf) {
interrupted = true;
// We have a waiting dispacther if and only if bf.length is
// zero. In that case, we need to give it a death kiss.
if (bf.length() == 0) {
bf.notify();
}
}
}
/**
* The dispatching strategy is to wait until there are events in the buffer
* to process. After having processed an event, we release the monitor
* (variable bf) so that new events can be placed in the buffer, instead of
* keeping the monitor and processing the remaining events in the buffer.
*
* <p>
* Other approaches might yield better results.
* </p>
*/
public void run() {
//Category cat = Category.getInstance(Dispatcher.class.getName());
LoggingEvent event;
while (true) {
synchronized (bf) {
if (bf.length() == 0) {
// Exit loop if interrupted but only if the the buffer is empty.
if (interrupted) {
//cat.info("Exiting.");
break;
}
try {
//LogLog.debug("Waiting for new event to dispatch.");
bf.wait();
} catch (InterruptedException e) {
break;
}
}
event = bf.get();
if (bf.wasFull()) {
//LogLog.debug("Notifying AsyncAppender about freed space.");
bf.notify();
}
}
// synchronized
synchronized (container.aai) {
if ((aai != null) && (event != null)) {
aai.appendLoopOnAppenders(event);
}
}
}
// while
// close and remove all appenders
aai.removeAllAppenders();
}
}