本文主要研究一下logback的DuplicateMessageFilter
ch/qos/logback/classic/turbo/TurboFilter.java
public abstract class TurboFilter extends ContextAwareBase implements LifeCycle {
private String name;
boolean start = false;
/**
* Make a decision based on the multiple parameters passed as arguments. The
* returned value should be one of {@link FilterReply#DENY}
,
* {@link FilterReply#NEUTRAL}
, or
* {@link FilterReply#ACCEPT}
.
*
* @param marker
* @param logger
* @param level
* @param format
* @param params
* @param t
* @return
*/
public abstract FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params,
Throwable t);
public void start() {
this.start = true;
}
public boolean isStarted() {
return this.start;
}
public void stop() {
this.start = false;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
TurboFilter继承了ContextAwareBase,声明实现LifeCycle接口,它定义了decide方法由子类实现
ch/qos/logback/classic/turbo/DuplicateMessageFilter.java
public class DuplicateMessageFilter extends TurboFilter {
/**
* The default cache size.
*/
public static final int DEFAULT_CACHE_SIZE = 100;
/**
* The default number of allows repetitions.
*/
public static final int DEFAULT_ALLOWED_REPETITIONS = 5;
public int allowedRepetitions = DEFAULT_ALLOWED_REPETITIONS;
public int cacheSize = DEFAULT_CACHE_SIZE;
private LRUMessageCache msgCache;
@Override
public void start() {
msgCache = new LRUMessageCache(cacheSize);
super.start();
}
@Override
public void stop() {
msgCache.clear();
msgCache = null;
super.stop();
}
@Override
public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) {
int count = msgCache.getMessageCountAndThenIncrement(format);
if (count <= allowedRepetitions) {
return FilterReply.NEUTRAL;
} else {
return FilterReply.DENY;
}
}
public int getAllowedRepetitions() {
return allowedRepetitions;
}
/**
* The allowed number of repetitions before
*
* @param allowedRepetitions
*/
public void setAllowedRepetitions(int allowedRepetitions) {
this.allowedRepetitions = allowedRepetitions;
}
public int getCacheSize() {
return cacheSize;
}
public void setCacheSize(int cacheSize) {
this.cacheSize = cacheSize;
}
}
DuplicateMessageFilter继承了TurboFilter,它使用了LRUMessageCache(
默认大小100
)来缓存format,decide方法会执行getMessageCountAndThenIncrement,若超出allowedRepetitions(默认5
)则返回FilterReply.DENY,否则返回FilterReply.NEUTRAL
ch/qos/logback/classic/turbo/LRUMessageCache.java
class LRUMessageCache extends LinkedHashMap {
private static final long serialVersionUID = 1L;
final int cacheSize;
LRUMessageCache(int cacheSize) {
super((int) (cacheSize * (4.0f / 3)), 0.75f, true);
if (cacheSize < 1) {
throw new IllegalArgumentException("Cache size cannot be smaller than 1");
}
this.cacheSize = cacheSize;
}
int getMessageCountAndThenIncrement(String msg) {
// don't insert null elements
if (msg == null) {
return 0;
}
Integer i;
// LinkedHashMap is not LinkedHashMap. See also LBCLASSIC-255
synchronized (this) {
i = super.get(msg);
if (i == null) {
i = 0;
} else {
i = i + 1;
}
super.put(msg, i);
}
return i;
}
// called indirectly by get() or put() which are already supposed to be
// called from within a synchronized block
protected boolean removeEldestEntry(Map.Entry eldest) {
return (size() > cacheSize);
}
@Override
synchronized public void clear() {
super.clear();
}
}
LRUMessageCache继承了LinkedHashMap,其初始size为
cacheSize * (4.0f / 3)
,getMessageCountAndThenIncrement方法内部通过synchronized加锁获取指定msg的次数,不存在则设置为0,存在则递增;其removeEldestEntry方法判断size() > cacheSize
DuplicateMessageFilter继承了TurboFilter,它使用了LRUMessageCache(默认大小100
)来缓存format,decide方法会执行getMessageCountAndThenIncrement,若超出allowedRepetitions(默认5
)则返回FilterReply.DENY,否则返回FilterReply.NEUTRAL。