reactor.logback.AsyncAppender Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of reactor-logback Show documentation
Show all versions of reactor-logback Show documentation
Async Logback appender implementation
package reactor.logback;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.LogbackException;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.*;
import reactor.core.processor.Operation;
import reactor.core.processor.Processor;
import reactor.core.processor.spec.ProcessorSpec;
import reactor.function.Consumer;
import reactor.function.Supplier;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/**
* A Logback {@literal Appender} implementation that uses a Reactor {@link reactor.core.processor.Processor} internally
* to queue events to a single-writer thread. This implementation doesn't do any actually appending itself, it just
* delegates to a "real" appender but it uses the efficient queueing mechanism of the {@literal RingBuffer} to do so.
*
* @author Jon Brisbin
*/
public class AsyncAppender
extends ContextAwareBase
implements Appender,
AppenderAttachable {
private final AppenderAttachableImpl aai = new AppenderAttachableImpl();
private final FilterAttachableImpl fai = new FilterAttachableImpl();
private final AtomicReference> delegate = new AtomicReference>();
private String name;
private Processor processor;
private long backlog = 1024 * 1024;
private boolean includeCallerData = false;
private boolean started = false;
public long getBacklog() {
return backlog;
}
public void setBacklog(long backlog) {
this.backlog = backlog;
}
public boolean isIncludeCallerData() {
return includeCallerData;
}
public void setIncludeCallerData(final boolean includeCallerData) {
this.includeCallerData = includeCallerData;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public boolean isStarted() {
return started;
}
@Override
public void doAppend(ILoggingEvent evt) throws LogbackException {
if (getFilterChainDecision(evt) == FilterReply.DENY) {
return;
}
evt.prepareForDeferredProcessing();
if (includeCallerData) {
evt.getCallerData();
}
try {
queueLoggingEvent(evt);
} catch (Throwable t) {
addError(t.getMessage(), t);
}
}
@Override
public void start() {
if (null != delegate.get()) {
delegate.get().start();
}
processor = new ProcessorSpec()
.dataSupplier(new Supplier() {
@Override
public LogEvent get() {
return new LogEvent();
}
})
.multiThreadedProducer()
.dataBufferSize((int) backlog)
.when(Throwable.class, new Consumer() {
@Override
public void accept(Throwable throwable) {
addError(throwable.getMessage(), throwable);
}
})
.consume(new Consumer() {
@Override
public void accept(LogEvent evt) {
loggingEventDequeued(evt.event);
}
})
.get();
try {
doStart();
} catch (Throwable t) {
addError(t.getMessage(), t);
} finally {
started = true;
}
}
@Override
public void stop() {
if (null != delegate.get()) {
delegate.get().stop();
}
aai.detachAndStopAllAppenders();
processor.shutdown();
try {
doStop();
} catch (Throwable t) {
addError(t.getMessage(), t);
} finally {
started = false;
}
}
@Override
public void addFilter(Filter newFilter) {
fai.addFilter(newFilter);
}
@Override
public void clearAllFilters() {
fai.clearAllFilters();
}
@Override
public List> getCopyOfAttachedFiltersList() {
return fai.getCopyOfAttachedFiltersList();
}
@Override
public FilterReply getFilterChainDecision(ILoggingEvent event) {
return fai.getFilterChainDecision(event);
}
@Override
public void addAppender(Appender newAppender) {
if (delegate.compareAndSet(null, newAppender)) {
aai.addAppender(newAppender);
} else {
throw new IllegalArgumentException(delegate.get() + " already attached.");
}
}
@Override
public Iterator> iteratorForAppenders() {
return aai.iteratorForAppenders();
}
@Override
public Appender getAppender(String name) {
return aai.getAppender(name);
}
@Override
public boolean isAttached(Appender appender) {
return aai.isAttached(appender);
}
@Override
public void detachAndStopAllAppenders() {
aai.detachAndStopAllAppenders();
}
@Override
public boolean detachAppender(Appender appender) {
return aai.detachAppender(appender);
}
@Override
public boolean detachAppender(String name) {
return aai.detachAppender(name);
}
protected AppenderAttachableImpl getAppenderImpl() {
return aai;
}
protected void doStart() {
}
protected void doStop() {
}
protected void queueLoggingEvent(ILoggingEvent evt) {
if (null != delegate.get()) {
Operation op = processor.prepare();
op.get().event = evt;
op.commit();
}
}
protected void loggingEventDequeued(ILoggingEvent evt) {
aai.appendLoopOnAppenders(evt);
}
private static class LogEvent {
ILoggingEvent event;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy