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的映射,创建的是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实现了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源码解读的详细内容,更多关于logback MarkerFilter的资料请关注脚本之家其它相关文章!
最新评论