package io.dropwizard.logging;
import ch.qos.logback.classic.AsyncAppender;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.filter.ThresholdFilter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.AsyncAppenderBase;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.spi.FilterAttachable;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Strings;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.util.TimeZone;
/**
* A base implementation of {@link AppenderFactory}.
* <p/>
* <b>Configuration Parameters:</b>
* <table>
* <tr>
* <td>Name</td>
* <td>Default</td>
* <td>Description</td>
* </tr>
* <tr>
* <td>{@code threshold}</td>
* <td>ALL</td>
* <td>The minimum event level the appender will handle.</td>
* </tr>
* <tr>
* <td>{@code logFormat}</td>
* <td>(none)</td>
* <td>An appender-specific log format.</td>
* </tr>
* <tr>
* <td>{@code queueSize}</td>
* <td>{@link AsyncAppenderBase}</td>
* <td>The maximum capacity of the blocking queue.</td>
* </tr>
* <tr>
* <td>{@code discardingThreshold}</td>
* <td>{@link AsyncAppenderBase}</td>
* <td>
* By default, when the blocking queue has 20% capacity remaining,
* it will drop events of level TRACE, DEBUG and INFO, keeping only
* events of level WARN and ERROR. To keep all events, set discardingThreshold to 0.
* </td>
* </tr>
* </table>
*/
public abstract class AbstractAppenderFactory implements AppenderFactory {
@NotNull
protected Level threshold = Level.ALL;
protected String logFormat;
@Min(1)
@Max(Integer.MAX_VALUE)
private int queueSize = AsyncAppenderBase.DEFAULT_QUEUE_SIZE;
private int discardingThreshold = -1;
@JsonProperty
public int getQueueSize() {
return queueSize;
}
@JsonProperty
public void setQueueSize(int queueSize) {
this.queueSize = queueSize;
}
@JsonProperty
public int getDiscardingThreshold() {
return discardingThreshold;
}
@JsonProperty
public void setDiscardingThreshold(int discardingThreshold) {
this.discardingThreshold = discardingThreshold;
}
@JsonProperty
public Level getThreshold() {
return threshold;
}
@JsonProperty
public void setThreshold(Level threshold) {
this.threshold = threshold;
}
@JsonProperty
public String getLogFormat() {
return logFormat;
}
@JsonProperty
public void setLogFormat(String logFormat) {
this.logFormat = logFormat;
}
protected Appender<ILoggingEvent> wrapAsync(Appender<ILoggingEvent> appender) {
return wrapAsync(appender, appender.getContext());
}
protected Appender<ILoggingEvent> wrapAsync(Appender<ILoggingEvent> appender, Context context) {
final AsyncAppender asyncAppender = new AsyncAppender();
asyncAppender.setQueueSize(queueSize);
asyncAppender.setDiscardingThreshold(discardingThreshold);
asyncAppender.setContext(context);
asyncAppender.setName("async-" + appender.getName());
asyncAppender.addAppender(appender);
asyncAppender.start();
return asyncAppender;
}
protected void addThresholdFilter(FilterAttachable<ILoggingEvent> appender, Level threshold) {
final ThresholdFilter filter = new ThresholdFilter();
filter.setLevel(threshold.toString());
filter.start();
appender.addFilter(filter);
}
protected DropwizardLayout buildLayout(LoggerContext context, TimeZone timeZone) {
final DropwizardLayout formatter = new DropwizardLayout(context, timeZone);
if (!Strings.isNullOrEmpty(logFormat)) {
formatter.setPattern(logFormat);
}
formatter.start();
return formatter;
}
}