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 <[email protected]> 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 <[email protected]>
> 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 <[email protected]> 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);
>>>> }
>>>>
>>>> }
>>>>
>>
>>