logback標記日志過濾器MarkerFilter源碼解讀
序
本文主要研究一下logback的MarkerFilter
MarkerFilter
ch/qos/logback/classic/turbo/MarkerFilter.java
public class MarkerFilter extends MatchingFilter {
Marker markerToMatch;
@Override
public void start() {
if (markerToMatch != null) {
super.start();
} else {
addError("The marker property must be set for [" + getName() + "]");
}
}
@Override
public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) {
if (!isStarted()) {
return FilterReply.NEUTRAL;
}
if (marker == null) {
return onMismatch;
}
if (marker.contains(markerToMatch)) {
return onMatch;
} else {
return onMismatch;
}
}
/**
* The marker to match in the event.
*
* @param markerStr
*/
public void setMarker(String markerStr) {
if (markerStr != null) {
this.markerToMatch = MarkerFactory.getMarker(markerStr);
}
}
}MarkerFilter定義了markerToMatch屬性,其decide方法對于傳入的marker為null返回onMismatch,對于包含markerToMatch的返回onMatch,否則返回onMismatch
MarkerFactory
org/slf4j/MarkerFactory.java
public class MarkerFactory {
static IMarkerFactory MARKER_FACTORY;
private MarkerFactory() {
}
// this is where the binding happens
static {
SLF4JServiceProvider provider = LoggerFactory.getProvider();
if (provider != null) {
MARKER_FACTORY = provider.getMarkerFactory();
} else {
Util.report("Failed to find provider");
Util.report("Defaulting to BasicMarkerFactory.");
MARKER_FACTORY = new BasicMarkerFactory();
}
}
/**
* Return a Marker instance as specified by the name parameter using the
* previously bound {@link IMarkerFactory}instance.
*
* @param name
* The name of the {@link Marker} object to return.
* @return marker
*/
public static Marker getMarker(String name) {
return MARKER_FACTORY.getMarker(name);
}
/**
* Create a marker which is detached (even at birth) from the MarkerFactory.
*
* @param name the name of the marker
* @return a dangling marker
* @since 1.5.1
*/
public static Marker getDetachedMarker(String name) {
return MARKER_FACTORY.getDetachedMarker(name);
}
/**
* Return the {@link IMarkerFactory}instance in use.
*
* <p>The IMarkerFactory instance is usually bound with this class at
* compile time.
*
* @return the IMarkerFactory instance in use
*/
public static IMarkerFactory getIMarkerFactory() {
return MARKER_FACTORY;
}
}MarkerFactory通過static方法來初始化MARKER_FACTORY,若SLF4JServiceProvider不為null則取provider.getMarkerFactory(),否則取BasicMarkerFactory
BasicMarkerFactory
org/slf4j/helpers/BasicMarkerFactory.java
public class BasicMarkerFactory implements IMarkerFactory {
private final ConcurrentMap<String, Marker> markerMap = new ConcurrentHashMap<>();
/**
* Regular users should <em>not</em> create
* <code>BasicMarkerFactory</code> instances. <code>Marker</code>
* instances can be obtained using the static {@link
* org.slf4j.MarkerFactory#getMarker} method.
*/
public BasicMarkerFactory() {
}
/**
* Manufacture a {@link BasicMarker} instance by name. If the instance has been
* created earlier, return the previously created instance.
*
* @param name the name of the marker to be created
* @return a Marker instance
*/
public Marker getMarker(String name) {
if (name == null) {
throw new IllegalArgumentException("Marker name cannot be null");
}
Marker marker = markerMap.get(name);
if (marker == null) {
marker = new BasicMarker(name);
Marker oldMarker = markerMap.putIfAbsent(name, marker);
if (oldMarker != null) {
marker = oldMarker;
}
}
return marker;
}
/**
* Does the name marked already exist?
*/
public boolean exists(String name) {
if (name == null) {
return false;
}
return markerMap.containsKey(name);
}
public boolean detachMarker(String name) {
if (name == null) {
return false;
}
return (markerMap.remove(name) != null);
}
public Marker getDetachedMarker(String name) {
return new BasicMarker(name);
}
}BasicMarkerFactory通過ConcurrentMap來存儲string與Marker的映射,創(chuàng)建的是BasicMarker
Marker
org/slf4j/Marker.java
public interface Marker extends Serializable {
/**
* This constant represents any marker, including a null marker.
*/
public final String ANY_MARKER = "*";
/**
* This constant represents any non-null marker.
*/
public final String ANY_NON_NULL_MARKER = "+";
/**
* Get the name of this Marker.
*
* @return name of marker
*/
public String getName();
/**
* Add a reference to another Marker.
*
* <p>Note that the fluent API allows adding multiple markers to a logging statement.
* It is often preferable to use multiple markers instead of nested markers.
* </p>
*
* @param reference
* a reference to another marker
* @throws IllegalArgumentException
* if 'reference' is null
*/
public void add(Marker reference);
/**
* Remove a marker reference.
*
* @param reference
* the marker reference to remove
* @return true if reference could be found and removed, false otherwise.
*/
public boolean remove(Marker reference);
/**
* @deprecated Replaced by {@link #hasReferences()}.
*/
@Deprecated
public boolean hasChildren();
/**
* Does this marker have any references?
*
* @return true if this marker has one or more references, false otherwise.
*/
public boolean hasReferences();
/**
* Returns an Iterator which can be used to iterate over the references of this
* marker. An empty iterator is returned when this marker has no references.
*
* @return Iterator over the references of this marker
*/
public Iterator<Marker> iterator();
/**
* Does this marker contain a reference to the 'other' marker? Marker A is defined
* to contain marker B, if A == B or if B is referenced by A, or if B is referenced
* by any one of A's references (recursively).
*
* @param other
* The marker to test for inclusion.
* @throws IllegalArgumentException
* if 'other' is null
* @return Whether this marker contains the other marker.
*/
public boolean contains(Marker other);
/**
* Does this marker contain the marker named 'name'?
*
* If 'name' is null the returned value is always false.
*
* @param name The marker name to test for inclusion.
* @return Whether this marker contains the other marker.
*/
public boolean contains(String name);
/**
* Markers are considered equal if they have the same name.
*
* @param o
* @return true, if this.name equals o.name
*
* @since 1.5.1
*/
public boolean equals(Object o);
/**
* Compute the hash code based on the name of this marker.
* Note that markers are considered equal if they have the same name.
*
* @return the computed hashCode
* @since 1.5.1
*/
public int hashCode();
}Marker接口定義了getName、add、remove、hasReferences、iterator、contains、equals、hashCode方法
BasicMarker
org/slf4j/helpers/BasicMarker.java
public class BasicMarker implements Marker {
private static final long serialVersionUID = -2849567615646933777L;
private final String name;
private final List<Marker> referenceList = new CopyOnWriteArrayList<>();
BasicMarker(String name) {
if (name == null) {
throw new IllegalArgumentException("A marker name cannot be null");
}
this.name = name;
}
public String getName() {
return name;
}
public void add(Marker reference) {
if (reference == null) {
throw new IllegalArgumentException("A null value cannot be added to a Marker as reference.");
}
// no point in adding the reference multiple times
if (this.contains(reference)) {
return;
} else if (reference.contains(this)) { // avoid recursion
// a potential reference should not hold its future "parent" as a reference
return;
} else {
referenceList.add(reference);
}
}
public boolean hasReferences() {
return (referenceList.size() > 0);
}
@Deprecated
public boolean hasChildren() {
return hasReferences();
}
public Iterator<Marker> iterator() {
return referenceList.iterator();
}
public boolean remove(Marker referenceToRemove) {
return referenceList.remove(referenceToRemove);
}
public boolean contains(Marker other) {
if (other == null) {
throw new IllegalArgumentException("Other cannot be null");
}
if (this.equals(other)) {
return true;
}
if (hasReferences()) {
for (Marker ref : referenceList) {
if (ref.contains(other)) {
return true;
}
}
}
return false;
}
/**
* This method is mainly used with Expression Evaluators.
*/
public boolean contains(String name) {
if (name == null) {
throw new IllegalArgumentException("Other cannot be null");
}
if (this.name.equals(name)) {
return true;
}
if (hasReferences()) {
for (Marker ref : referenceList) {
if (ref.contains(name)) {
return true;
}
}
}
return false;
}
private static final String OPEN = "[ ";
private static final String CLOSE = " ]";
private static final String SEP = ", ";
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Marker))
return false;
final Marker other = (Marker) obj;
return name.equals(other.getName());
}
public int hashCode() {
return name.hashCode();
}
public String toString() {
if (!this.hasReferences()) {
return this.getName();
}
Iterator<Marker> it = this.iterator();
Marker reference;
StringBuilder sb = new StringBuilder(this.getName());
sb.append(' ').append(OPEN);
while (it.hasNext()) {
reference = it.next();
sb.append(reference.getName());
if (it.hasNext()) {
sb.append(SEP);
}
}
sb.append(CLOSE);
return sb.toString();
}
}BasicMarker實現(xiàn)了Marker接口,它定義了一個CopyOnWriteArrayList類型的referenceList
示例
配置
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<turboFilter class="ch.qos.logback.classic.turbo.MDCFilter">
<MDCKey>username</MDCKey>
<Value>sebastien</Value>
<OnMatch>ACCEPT</OnMatch>
</turboFilter>
<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
<Marker>billing</Marker>
<OnMatch>DENY</OnMatch>
</turboFilter>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%date [%thread] %-5level %logger - %msg%n</Pattern>
</layout>
</appender>
<root level="info">
<appender-ref ref="console" />
</root>
</configuration>使用
Marker billing = MarkerFactory.getMarker("billing");
logger.error(billing, "billing statement {}", i);小結
logback提供了MarkerFilter來支持slf4j的Marker,可以通過MarkerFactory.getMarker獲取marker,然后在logger中使用,而配置文件可以配置MarkerFilter,設置指定的marker的onMatch或者onMismatch行為。
以上就是logback標記日志過濾器MarkerFilter源碼解讀的詳細內(nèi)容,更多關于logback MarkerFilter的資料請關注腳本之家其它相關文章!
相關文章
Java中Collections.emptyList()的注意事項
這篇文章主要給大家介紹了關于Java中Collections.emptyList()的注意事項,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-03-03
SpringBoot統(tǒng)一數(shù)據(jù)返回的幾種方式
在Web應用程序開發(fā)中,統(tǒng)一數(shù)據(jù)返回格式對于前后端分離項目尤為重要,本文就來介紹一下SpringBoot統(tǒng)一數(shù)據(jù)返回的幾種方式,具有一定的參考價值,感興趣的可以了解一下2024-07-07
Java二維數(shù)組與稀疏數(shù)組相互轉換實現(xiàn)詳解
在某些應用場景中需要大量的二維數(shù)組來進行數(shù)據(jù)存儲,但是二維數(shù)組中卻有著大量的無用的位置占據(jù)著內(nèi)存空間,稀疏數(shù)組就是為了優(yōu)化二維數(shù)組,節(jié)省內(nèi)存空間2022-09-09
SpringBoot整合Redis實現(xiàn)訪問量統(tǒng)計的示例代碼
本文主要介紹了SpringBoot整合Redis實現(xiàn)訪問量統(tǒng)計的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02

