Comprehensive SLF4J implementation providing enterprise-grade logging with flexible configuration, high performance, and extensive appender ecosystem for Java applications.
—
Event filtering mechanisms for controlling which log events are processed at various levels of the logging pipeline. Filters provide fine-grained control over log processing with minimal performance impact.
Base interface and functionality for all filters.
/**
* Core filter interface for controlling log event processing
*/
public abstract class Filter<E> extends ContextAwareBase implements LifeCycle {
private String name;
/**
* Decide whether to accept, deny, or remain neutral about an event
*/
public abstract FilterReply decide(E event);
public String getName();
public void setName(String name);
// LifeCycle methods
public void start();
public void stop();
public boolean isStarted();
}
/**
* Filter decision enumeration
*/
public enum FilterReply {
DENY, // Reject the event immediately
NEUTRAL, // Let other filters decide
ACCEPT // Accept the event immediately
}
/**
* Interface for components that can have filters attached
*/
public interface FilterAttachable<E> {
void addFilter(Filter<E> newFilter);
void clearAllFilters();
List<Filter<E>> getCopyOfAttachedFiltersList();
FilterReply getFilterChainDecision(E event);
}Filters based on logging levels.
/**
* Filter that accepts or denies events based on exact level match
*/
public class LevelFilter extends Filter<ILoggingEvent> {
Level level;
FilterReply onMatch = FilterReply.NEUTRAL;
FilterReply onMismatch = FilterReply.NEUTRAL;
/**
* Set the level to match against
*/
public void setLevel(Level level);
public Level getLevel();
/**
* Set action when level matches
*/
public void setOnMatch(FilterReply reply);
public FilterReply getOnMatch();
/**
* Set action when level doesn't match
*/
public void setOnMismatch(FilterReply reply);
public FilterReply getOnMismatch();
@Override
public FilterReply decide(ILoggingEvent event);
}
/**
* Filter that denies events below a threshold level
*/
public class ThresholdFilter extends Filter<ILoggingEvent> {
Level level;
/**
* Set the minimum level threshold
*/
public void setLevel(Level level);
public Level getLevel();
@Override
public FilterReply decide(ILoggingEvent event);
}Usage Examples:
import ch.qos.logback.classic.filter.LevelFilter;
import ch.qos.logback.classic.filter.ThresholdFilter;
// Level filter - only accept INFO events
LevelFilter levelFilter = new LevelFilter();
levelFilter.setContext(loggerContext);
levelFilter.setLevel(Level.INFO);
levelFilter.setOnMatch(FilterReply.ACCEPT);
levelFilter.setOnMismatch(FilterReply.DENY);
levelFilter.start();
// Threshold filter - accept WARN and above
ThresholdFilter thresholdFilter = new ThresholdFilter();
thresholdFilter.setContext(loggerContext);
thresholdFilter.setLevel(Level.WARN);
thresholdFilter.start();
// Add to appender
appender.addFilter(levelFilter);High-performance filters that operate before LoggingEvent creation.
/**
* High-performance filter base class that operates before event creation
*/
public abstract class TurboFilter extends ContextAwareBase implements LifeCycle {
private String name;
/**
* Decide on logging event before LoggingEvent is created
* @param marker the marker (can be null)
* @param logger the logger
* @param level the level
* @param format the message format
* @param params message parameters
* @param t throwable (can be null)
*/
public abstract FilterReply decide(Marker marker, Logger logger, Level level,
String format, Object[] params, Throwable t);
public String getName();
public void setName(String name);
public void start();
public void stop();
public boolean isStarted();
}
/**
* Container for turbo filters with evaluation logic
*/
public final class TurboFilterList extends ArrayList<TurboFilter> {
/**
* Evaluate all turbo filters for an event
*/
public FilterReply getTurboFilterChainDecision(Marker marker, Logger logger, Level level,
String format, Object[] params, Throwable t);
}Commonly used turbo filter implementations.
/**
* Filter duplicate messages to reduce log noise
*/
public class DuplicateMessageFilter extends TurboFilter {
public static final int DEFAULT_CACHE_SIZE = 100;
public static final int DEFAULT_ALLOWED_REPETITIONS = 5;
private int allowedRepetitions = DEFAULT_ALLOWED_REPETITIONS;
private int cacheSize = DEFAULT_CACHE_SIZE;
private LRUMessageCache msgCache;
/**
* Set number of allowed repetitions before filtering
*/
public int getAllowedRepetitions();
public void setAllowedRepetitions(int allowedRepetitions);
/**
* Set cache size for tracking messages
*/
public int getCacheSize();
public void setCacheSize(int cacheSize);
@Override
public FilterReply decide(Marker marker, Logger logger, Level level,
String format, Object[] params, Throwable t);
}
/**
* Filter based on MDC values
*/
public class MDCFilter extends TurboFilter {
String MDCKey;
String value;
FilterReply onMatch = FilterReply.NEUTRAL;
FilterReply onMismatch = FilterReply.NEUTRAL;
/**
* Set the MDC key to check
*/
public void setMDCKey(String MDCKey);
public String getMDCKey();
/**
* Set the value to match against
*/
public void setValue(String value);
public String getValue();
/**
* Set actions for match/mismatch
*/
public void setOnMatch(FilterReply reply);
public FilterReply getOnMatch();
public void setOnMismatch(FilterReply reply);
public FilterReply getOnMismatch();
@Override
public FilterReply decide(Marker marker, Logger logger, Level level,
String format, Object[] params, Throwable t);
}
/**
* Filter based on SLF4J markers
*/
public class MarkerFilter extends TurboFilter {
Marker markerToMatch;
FilterReply onMatch = FilterReply.NEUTRAL;
FilterReply onMismatch = FilterReply.NEUTRAL;
/**
* Set the marker to match against
*/
public void setMarker(String markerStr);
public String getMarker();
/**
* Set actions for match/mismatch
*/
public void setOnMatch(FilterReply reply);
public FilterReply getOnMatch();
public void setOnMismatch(FilterReply reply);
public FilterReply getOnMismatch();
@Override
public FilterReply decide(Marker marker, Logger logger, Level level,
String format, Object[] params, Throwable t);
}
/**
* Dynamic threshold filter based on MDC values
*/
public class DynamicThresholdFilter extends TurboFilter {
private Map<String, Level> valueLevelMap = new HashMap<String, Level>();
private Level defaultThreshold;
private String key;
FilterReply onHigherOrEqual = FilterReply.NEUTRAL;
FilterReply onLower = FilterReply.DENY;
/**
* Set the MDC key to use for threshold lookup
*/
public String getKey();
public void setKey(String key);
/**
* Set the default threshold when key not found in MDC
*/
public void setDefaultThreshold(Level defaultThreshold);
public Level getDefaultThreshold();
/**
* Add MDC value to level mapping
*/
public void addMDCValueLevelPair(MDCValueLevelPair mdcValueLevelPair);
/**
* Set actions for threshold comparison
*/
public void setOnHigherOrEqual(FilterReply reply);
public FilterReply getOnHigherOrEqual();
public void setOnLower(FilterReply reply);
public FilterReply getOnLower();
@Override
public FilterReply decide(Marker marker, Logger logger, Level level,
String format, Object[] params, Throwable t);
}
/**
* Reconfigure logback when configuration file changes
*/
public class ReconfigureOnChangeFilter extends TurboFilter implements ReconfigureOnChangeTask {
public static final long DEFAULT_REFRESH_PERIOD = 60 * 1000; // 1 minute
long refreshPeriod = DEFAULT_REFRESH_PERIOD;
URL mainConfigurationURL;
protected volatile long nextCheck;
ConfigurationWatchList configurationWatchList;
/**
* Set refresh period in milliseconds
*/
public void setRefreshPeriod(long refreshPeriod);
public long getRefreshPeriod();
@Override
public FilterReply decide(Marker marker, Logger logger, Level level,
String format, Object[] params, Throwable t);
}Advanced filtering using boolean expressions.
/**
* Base interface for event evaluators
*/
public interface EventEvaluator<E> extends ContextAware, LifeCycle {
/**
* Evaluate whether an event matches criteria
*/
boolean evaluate(E event) throws EvaluationException;
String getName();
void setName(String name);
}
/**
* Evaluator based on SLF4J markers
*/
public class OnMarkerEvaluator extends EventEvaluatorBase<ILoggingEvent> {
String markerStr;
Marker marker;
/**
* Set the marker to evaluate against
*/
public String getMarker();
public void setMarker(String markerStr);
@Override
public boolean evaluate(ILoggingEvent event) throws EvaluationException;
}
/**
* Evaluator that matches ERROR level events
*/
public class OnErrorEvaluator extends EventEvaluatorBase<ILoggingEvent> {
@Override
public boolean evaluate(ILoggingEvent event);
}
/**
* Evaluator based on exception matching
*/
public class ExceptionMatchEvaluator extends EventEvaluatorBase<ILoggingEvent> {
String exceptionClassName;
/**
* Set the exception class name to match
*/
public String getExceptionClassName();
public void setExceptionClassName(String exceptionClassName);
@Override
public boolean evaluate(ILoggingEvent event);
}import ch.qos.logback.classic.turbo.*;
import ch.qos.logback.classic.filter.*;
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
// Add turbo filters to context (evaluated first)
DuplicateMessageFilter dupFilter = new DuplicateMessageFilter();
dupFilter.setContext(context);
dupFilter.setAllowedRepetitions(3);
dupFilter.setCacheSize(200);
dupFilter.start();
context.addTurboFilter(dupFilter);
// MDC-based filtering
MDCFilter mdcFilter = new MDCFilter();
mdcFilter.setContext(context);
mdcFilter.setMDCKey("env");
mdcFilter.setValue("production");
mdcFilter.setOnMatch(FilterReply.ACCEPT);
mdcFilter.setOnMismatch(FilterReply.DENY);
mdcFilter.start();
context.addTurboFilter(mdcFilter);
// Add regular filter to appender
ThresholdFilter appenderFilter = new ThresholdFilter();
appenderFilter.setContext(context);
appenderFilter.setLevel(Level.WARN);
appenderFilter.start();
appender.addFilter(appenderFilter);// Different log levels for different users
DynamicThresholdFilter dynFilter = new DynamicThresholdFilter();
dynFilter.setContext(context);
dynFilter.setKey("userId");
dynFilter.setDefaultThreshold(Level.WARN);
// Admin users get DEBUG level
MDCValueLevelPair adminPair = new MDCValueLevelPair();
adminPair.setValue("admin");
adminPair.setLevel(Level.DEBUG);
dynFilter.addMDCValueLevelPair(adminPair);
// Developer users get INFO level
MDCValueLevelPair devPair = new MDCValueLevelPair();
devPair.setValue("developer");
devPair.setLevel(Level.INFO);
dynFilter.addMDCValueLevelPair(devPair);
dynFilter.start();
context.addTurboFilter(dynFilter);
// In application code:
MDC.put("userId", "admin");
logger.debug("This will be logged for admin users");
MDC.put("userId", "regular");
logger.debug("This will NOT be logged for regular users");import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
// Create markers
Marker PERFORMANCE = MarkerFactory.getMarker("PERFORMANCE");
Marker SECURITY = MarkerFactory.getMarker("SECURITY");
// Filter for performance logs only
MarkerFilter perfFilter = new MarkerFilter();
perfFilter.setContext(context);
perfFilter.setMarker("PERFORMANCE");
perfFilter.setOnMatch(FilterReply.ACCEPT);
perfFilter.setOnMismatch(FilterReply.DENY);
perfFilter.start();
// Add to specific appender
performanceAppender.addFilter(perfFilter);
// Usage in code
logger.info(PERFORMANCE, "Operation completed in {}ms", duration);
logger.warn(SECURITY, "Failed login attempt from {}", ipAddress);// Enable automatic reconfiguration on file changes
ReconfigureOnChangeFilter reconfFilter = new ReconfigureOnChangeFilter();
reconfFilter.setContext(context);
reconfFilter.setRefreshPeriod(30000); // Check every 30 seconds
reconfFilter.start();
context.addTurboFilter(reconfFilter);
// Logback will automatically reload when logback.xml changesInstall with Tessl CLI
npx tessl i tessl/maven-ch-qos-logback--logback-classic