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);
> }
>
> }
>