Yeah, you lost me. Your code has 

   private Result filter(final Level testLevel) {
       if (testLevel.isMoreSpecificThan(this.level)) {
           throw new FilterLoggingException(Objects.toString(testLevel));
       }
       return onMismatch;
   }

This isn’t returning a new type of Result, it is actually throwing an 
exception. If it was doing 
        return Result.FilterException;

Instead of the throw then I could understand what you are saying.

Ralph


> On Oct 9, 2024, at 9:55 AM, Gary Gregory <garydgreg...@gmail.com> wrote:
> 
> Hi Ralph,
> 
> Thank you for taking a peek.
> 
> I either did not explain myself clearly or in enough detail as I don't feel
> you fully grasped what I proposed ;-)
> 
> "Secondly, I don’t like that the only criteria it is able to use to
> determine whether to throw an exception is the log level."
> 
> It is _not_ only the log level, this would work with _any_ filter. I am
> _not_ proposing to add any _new_ filters, that's what I want to avoid. I
> propose the ability for any filter to be configured with "Result.THROW", a
> new Result value, which log4j-core would translate to throwing an exception.
> 
> "Filters are for determining whether log events should be logged ... It is
> more like an interceptor."
> 
> Yes, this proposal can make a filter look like an interceptor or an
> "interruptor" in this case.
> 
> Let me present it slightly differently:
> 
> I feel it's reasonable for Log4j to provide the ability to cause a unit
> test to fail if a log event meets a criterion. JUnit detects exceptions as
> test failures. Log4j can propagate exceptions if configured to do so. The
> last step missing is how to configure Log4j to throw an exception when a
> log event criterion is met. Log4j provides filters which is the closest
> feature for testing log events for criteria. So, it seems to me like
> filters are the best place to implement this feature. I don't think we need
> to invent something else.
> 
> HTH,
> Gary
> 
> 
> On Wed, Oct 9, 2024 at 11:11 AM Ralph Goers <ralph.go...@dslextreme.com>
> wrote:
> 
>> This just feels wrong. Filters are for determining whether log events
>> should be logged. This Filter doesn’t have anything to do with that. It is
>> more like an interceptor.
>> 
>> Secondly, I don’t like that the only criteria it is able to use to
>> determine whether to throw an exception is the log level.
>> 
>> This just feels way too specific.
>> 
>> Ralph
>> 
>>> On Oct 9, 2024, at 7:36 AM, Gary D. Gregory <ggreg...@apache.org> wrote:
>>> 
>>> 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);
>>>>   }
>>>> 
>>>> }
>>>> 
>> 
>> 

Reply via email to