Hi Ralph,

I'll try again:

As mentioned, I don't want to have to write this custom filter in the first
place.

I want to write:

    @SuppressWarnings("resource")
    @BeforeAll
    static void beforeAddFilter() {

LoggerContext.getContext(false).getLogger("org.hibernate").addFilter(ThresholdFilter.createFilter(Level.WARN,
*Result.THROW*, Result.NEUTRAL));
    }

The value Result.THROW does not exist today. This proposal is to:

- Add Result.THROW
- There is no need to modify any Filter impls.
- When Core sees Result.THROW result from a Filter, it throws a
FilterLoggingException.

I hope that helps make my proposal clearer :-)
TY,
Gary



On Wed, Oct 9, 2024 at 2:46 PM Ralph Goers <ralph.go...@dslextreme.com>
wrote:

> 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