
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
The newest version!
/*
* Copyright (c) 2011-2017 Pivotal Software Inc, All Rights Reserved.
*
* 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
*
* https://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 reactor.logback;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
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.AppenderAttachable;
import ch.qos.logback.core.spi.AppenderAttachableImpl;
import ch.qos.logback.core.spi.ContextAwareBase;
import ch.qos.logback.core.spi.FilterAttachableImpl;
import ch.qos.logback.core.spi.FilterReply;
import org.reactivestreams.Subscription;
import reactor.core.CoreSubscriber;
import reactor.core.publisher.WorkQueueProcessor;
/**
* A Logback {@literal Appender} implementation that uses a Reactor {@link
* reactor.core.publisher.TopicProcessor} 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
* @author Stephane Maldini
*/
public class AsyncAppender extends ContextAwareBase
implements Appender, AppenderAttachable,
CoreSubscriber {
private final AppenderAttachableImpl aai =
new AppenderAttachableImpl();
private final FilterAttachableImpl fai =
new FilterAttachableImpl();
private final AtomicReference> delegate =
new AtomicReference>();
private String name;
private WorkQueueProcessor processor;
private int backlog = 1024 * 1024;
private boolean includeCallerData = false;
private boolean started = false;
public int getBacklog() {
return backlog;
}
public void setBacklog(int 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() {
startDelegateAppender();
processor = WorkQueueProcessor.builder().name("logger")
.bufferSize(backlog)
.autoCancel(false)
.build();
processor.subscribe(this);
}
@Override
public void onSubscribe(Subscription s) {
try {
doStart();
}
catch (Throwable t) {
addError(t.getMessage(), t);
}
finally {
started = true;
s.request(Long.MAX_VALUE);
}
}
@Override
public void onNext(ILoggingEvent iLoggingEvent) {
aai.appendLoopOnAppenders(iLoggingEvent);
}
@Override
public void onError(Throwable t) {
addError(t.getMessage(), t);
}
@Override
public void onComplete() {
try {
Appender appender = delegate.getAndSet(null);
if (appender != null){
doStop();
appender.stop();
aai.detachAndStopAllAppenders();
}
}
catch (Throwable t) {
addError(t.getMessage(), t);
}
finally {
started = false;
}
}
private void startDelegateAppender() {
Appender delegateAppender = delegate.get();
if (null != delegateAppender && !delegateAppender.isStarted()) {
delegateAppender.start();
}
}
@Override
public void stop() {
processor.onComplete();
}
@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()) {
processor.onNext(evt);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy