io.dropwizard.logging.AbstractAppenderFactory Maven / Gradle / Ivy
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.core.Appender;
import ch.qos.logback.core.AsyncAppenderBase;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.LayoutBase;
import ch.qos.logback.core.pattern.PatternLayoutBase;
import ch.qos.logback.core.spi.DeferredProcessingAware;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.dropwizard.logback.ThrottlingAppenderWrapper;
import io.dropwizard.logging.async.AsyncAppenderFactory;
import io.dropwizard.logging.filter.FilterFactory;
import io.dropwizard.logging.layout.DiscoverableLayoutFactory;
import io.dropwizard.logging.layout.LayoutFactory;
import io.dropwizard.util.Strings;
import io.dropwizard.util.Duration;
import io.dropwizard.validation.MaxDuration;
import io.dropwizard.validation.MinDuration;
import javax.annotation.Nullable;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
/**
* A base implementation of {@link AppenderFactory}.
*
* Configuration Parameters:
*
*
* Name
* Default
* Description
*
*
* {@code threshold}
* ALL
* The minimum event level the appender will handle.
*
*
* {@code logFormat}
* (none)
* An appender-specific log format.
*
*
* {@code timeZone}
* {@code UTC}
*
* The time zone to which event timestamps will be converted.
* Ignored if logFormat is supplied.
*
*
*
* {@code queueSize}
* {@link AsyncAppenderBase}
* The maximum capacity of the blocking queue.
*
*
* {@code includeCallerData}
* {@link AsyncAppenderBase}
*
* Whether to include caller data, required for line numbers.
* Beware, is considered expensive.
*
*
*
* {@code discardingThreshold}
* {@link AsyncAppenderBase}
*
* 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.
*
*
*
* {@code messageRate}
*
* Maximum message rate: average duration between messages. Extra messages are discarded.
* This setting avoids flooding a paid logging service by accident.
* For example, a duration of 100ms allows for a maximum of 10 messages per second and 30s would mean
* 1 message every 30 seconds.
* The maximum acceptable duration is 1 minute.
* By default, this duration is not set and this feature is disabled.
*
*
*
* {@code filterFactories}
* (none)
*
* A list of {@link FilterFactory filters} to apply to the appender, in order,
* after the {@code threshold}.
*
*
*
*/
public abstract class AbstractAppenderFactory implements AppenderFactory {
@NotNull
protected Level threshold = Level.ALL;
@Nullable
protected String logFormat;
@Nullable
protected DiscoverableLayoutFactory layout;
@NotNull
protected TimeZone timeZone = TimeZone.getTimeZone("UTC");
@Min(1)
@Max(Integer.MAX_VALUE)
private int queueSize = AsyncAppenderBase.DEFAULT_QUEUE_SIZE;
private int discardingThreshold = -1;
@Nullable
@MinDuration(value = 0, unit = TimeUnit.SECONDS, inclusive = false)
@MaxDuration(value = 1, unit = TimeUnit.MINUTES)
private Duration messageRate;
private boolean includeCallerData = false;
private List> filterFactories = Collections.emptyList();
private boolean neverBlock = false;
@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;
}
/**
* @since 2.0
*/
@JsonProperty
@Nullable
public Duration getMessageRate() {
return messageRate;
}
/**
* @since 2.0
*/
@JsonProperty
public void setMessageRate(Duration messageRate) {
this.messageRate = messageRate;
}
@JsonProperty
public String getThreshold() {
return threshold.toString();
}
@JsonProperty
public void setThreshold(String threshold) {
this.threshold = DefaultLoggingFactory.toLevel(threshold);
}
@JsonProperty
@Nullable
public String getLogFormat() {
return logFormat;
}
@JsonProperty
public void setLogFormat(@Nullable String logFormat) {
this.logFormat = logFormat;
}
@JsonProperty
public TimeZone getTimeZone() {
return timeZone;
}
@JsonProperty
public void setTimeZone(String zoneId) {
this.timeZone = Strings.nullToEmpty(zoneId).equalsIgnoreCase("system") ? TimeZone.getDefault() :
TimeZone.getTimeZone(zoneId);
}
@JsonProperty
public void setTimeZone(TimeZone timeZone) {
this.timeZone = timeZone;
}
@JsonProperty
public boolean isIncludeCallerData() {
return includeCallerData;
}
@JsonProperty
public void setIncludeCallerData(boolean includeCallerData) {
this.includeCallerData = includeCallerData;
}
@JsonProperty
public List> getFilterFactories() {
return filterFactories;
}
@JsonProperty
public void setFilterFactories(List> appenders) {
this.filterFactories = new ArrayList<>(appenders);
}
@JsonProperty
public void setNeverBlock(boolean neverBlock) {
this.neverBlock = neverBlock;
}
@Nullable
public DiscoverableLayoutFactory> getLayout() {
return layout;
}
public void setLayout(@Nullable DiscoverableLayoutFactory layout) {
this.layout = layout;
}
protected Appender wrapAsync(Appender appender, AsyncAppenderFactory asyncAppenderFactory) {
return wrapAsync(appender, asyncAppenderFactory, appender.getContext());
}
protected Appender wrapAsync(Appender appender, AsyncAppenderFactory asyncAppenderFactory, Context context) {
final AsyncAppenderBase asyncAppender = asyncAppenderFactory.build();
if (asyncAppender instanceof AsyncAppender) {
((AsyncAppender) asyncAppender).setIncludeCallerData(includeCallerData);
}
asyncAppender.setQueueSize(queueSize);
asyncAppender.setDiscardingThreshold(discardingThreshold);
asyncAppender.setContext(context);
asyncAppender.setName("async-" + appender.getName());
asyncAppender.addAppender(appender);
asyncAppender.setNeverBlock(neverBlock);
asyncAppender.start();
if (messageRate == null) {
return asyncAppender;
} else {
return new ThrottlingAppenderWrapper<>(asyncAppender, messageRate.getQuantity(), messageRate.getUnit());
}
}
protected LayoutBase buildLayout(LoggerContext context, LayoutFactory defaultLayoutFactory) {
final LayoutBase layoutBase;
if (layout == null) {
final PatternLayoutBase patternLayoutBase = defaultLayoutFactory.build(context, timeZone);
if (!Strings.isNullOrEmpty(logFormat)) {
patternLayoutBase.setPattern(logFormat);
}
layoutBase = patternLayoutBase;
} else {
layoutBase = layout.build(context, timeZone);
}
layoutBase.start();
return layoutBase;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy