Typo, the new code would be: private static final Filter THROWING_FILTER = ThresholdFilter.createFilter(Level.WARN, Result.THROW, Result.NEUTRAL);
Sorry about that. Gary On 2024/10/09 14:34:15 "Gary D. Gregory" wrote: > Hi All: > > As a user, I want to programmatically configure Log4j to throw an exception > when a specific component logs a WARN event. > > Background: I am working with a large and complex stack that include > Hibernate in the mix. I just fixed a bug that, that as a side-effect, caused > Hibernate to log WARN events. As a check on possible regressions, I want to > make sure that a test class fails when Hibernate logs a WARN event. This > whole Maven module shares a log4j configuration file and, for now, I only > want this check on this one test class. > > My current implementation uses a custom filter called ThrowingThresholdFilter > [see end of message], a copy of our ThresholdFilter that throws a subclass of > LoggingException called FilterLoggingException when the configured Level is > matched. > > I also have happen to have other checks with other custom filters: > ThrowingLevelFilter and ThrowingStringMatchFilter. > > The only change in the configuration file is the use of the > “ignoreExceptions” attribute to a Console Appender. > > The test contains: > private static final Filter THROWING_FILTER = > ThrowingThresholdFilter.createFilter(Level.WARN, Result.NEUTRAL); > @SuppressWarnings("resource") > @BeforeAll > static void beforeAddFilter() { > > LoggerContext.getContext(false).getLogger("org.hibernate").addFilter(THROWING_FILTER); > } > > My proposal is to allow a user to _not_ define any custom filters by reusing > a new Result enum value called “Throw”. When a filter returns “Throw”, then > Log4j throws a new LoggingException subclass called FilterLoggingException. > > Then my test can replace: > > private static final Filter THROWING_FILTER = > ThrowingThresholdFilter.createFilter(Level.WARN, Result.NEUTRAL); > > and drop all custom filters. > > With: > > private static final Filter THROWING_FILTER = > ThresholdFilter.createFilter(Level.WARN, Result.NEUTRAL); > > WDYT? > > Gary > > package my.company; > > import java.util.Objects; > > import org.apache.logging.log4j.Level; > import org.apache.logging.log4j.LoggingException; > import org.apache.logging.log4j.Marker; > import org.apache.logging.log4j.core.Filter; > import org.apache.logging.log4j.core.LogEvent; > import org.apache.logging.log4j.core.Logger; > import org.apache.logging.log4j.core.config.Node; > import org.apache.logging.log4j.core.config.plugins.Plugin; > import org.apache.logging.log4j.core.config.plugins.PluginAttribute; > import org.apache.logging.log4j.core.config.plugins.PluginFactory; > import org.apache.logging.log4j.core.filter.AbstractFilter; > import org.apache.logging.log4j.message.Message; > import org.apache.logging.log4j.util.PerformanceSensitive; > > /** > * This filter returns the onMatch result if the level in the {@link > LogEvent} is the same or more specific > * than the configured level and the {@code onMismatch} value otherwise. For > example, if the ThresholdFilter > * is configured with Level {@code ERROR} and the LogEvent contains Level > {@code DEBUG} then the {@code onMismatch} value will > * be returned since {@code ERROR} events are more specific than {@code > DEBUG}. > * <p> > * The default Level is {@code ERROR}. > * </p> > * > * @see Level#isMoreSpecificThan(Level) > */ > @Plugin(name = "ThrowingThresholdFilter", category = Node.CATEGORY, > elementType = Filter.ELEMENT_TYPE, printObject = true) > @PerformanceSensitive("allocation") > public final class ThrowingThresholdFilter extends AbstractFilter { > > public static class FilterLoggingException extends LoggingException { > > private static final long serialVersionUID = 1L; > > public FilterLoggingException(String message) { > super(message); > } > > } > > private final Level level; > > private ThrowingThresholdFilter(final Level level, final Result > onMismatch) { > super(Result.NEUTRAL, onMismatch); > this.level = level; > } > > @Override > public Result filter(final Logger logger, final Level testLevel, final > Marker marker, final String msg, > final Object... params) { > return filter(testLevel); > } > > @Override > public Result filter(final Logger logger, final Level testLevel, final > Marker marker, final Object msg, > final Throwable t) { > return filter(testLevel); > } > > @Override > public Result filter(final Logger logger, final Level testLevel, final > Marker marker, final Message msg, > final Throwable t) { > return filter(testLevel); > } > > @Override > public Result filter(final LogEvent event) { > return filter(event.getLevel()); > } > > private Result filter(final Level testLevel) { > if (testLevel.isMoreSpecificThan(this.level)) { > throw new FilterLoggingException(Objects.toString(testLevel)); > } > return onMismatch; > } > > @Override > public Result filter(final Logger logger, final Level level, final Marker > marker, final String msg, > final Object p0) { > return filter(level); > } > > @Override > public Result filter(final Logger logger, final Level level, final Marker > marker, final String msg, > final Object p0, final Object p1) { > return filter(level); > } > > @Override > public Result filter(final Logger logger, final Level level, final Marker > marker, final String msg, > final Object p0, final Object p1, final Object p2) { > return filter(level); > } > > @Override > public Result filter(final Logger logger, final Level level, final Marker > marker, final String msg, > final Object p0, final Object p1, final Object p2, final Object > p3) { > return filter(level); > } > > @Override > public Result filter(final Logger logger, final Level level, final Marker > marker, final String msg, > final Object p0, final Object p1, final Object p2, final Object > p3, > final Object p4) { > return filter(level); > } > > @Override > public Result filter(final Logger logger, final Level level, final Marker > marker, final String msg, > final Object p0, final Object p1, final Object p2, final Object > p3, > final Object p4, final Object p5) { > return filter(level); > } > > @Override > public Result filter(final Logger logger, final Level level, final Marker > marker, final String msg, > final Object p0, final Object p1, final Object p2, final Object > p3, > final Object p4, final Object p5, final Object p6) { > return filter(level); > } > > @Override > public Result filter(final Logger logger, final Level level, final Marker > marker, final String msg, > final Object p0, final Object p1, final Object p2, final Object > p3, > final Object p4, final Object p5, final Object p6, > final Object p7) { > return filter(level); > } > > @Override > public Result filter(final Logger logger, final Level level, final Marker > marker, final String msg, > final Object p0, final Object p1, final Object p2, final Object > p3, > final Object p4, final Object p5, final Object p6, > final Object p7, final Object p8) { > return filter(level); > } > > @Override > public Result filter(final Logger logger, final Level level, final Marker > marker, final String msg, > final Object p0, final Object p1, final Object p2, final Object > p3, > final Object p4, final Object p5, final Object p6, > final Object p7, final Object p8, final Object p9) { > return filter(level); > } > > public Level getLevel() { > return level; > } > > @Override > public String toString() { > return level.toString(); > } > > /** > * Creates a ThrowingThresholdFilter. > * @param level The log Level. > * @param mismatch The action to take on a mismatch. > * @return The created ThrowingThresholdFilter. > */ > // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder > @PluginFactory > public static ThrowingThresholdFilter createFilter( > @PluginAttribute("level") final Level level, > @PluginAttribute("onMismatch") final Result mismatch) { > final Level actualLevel = level == null ? Level.ERROR : level; > final Result onMismatch = mismatch == null ? Result.DENY : mismatch; > return new ThrowingThresholdFilter(actualLevel, onMismatch); > } > > } >