From e8bbd1d78275103b2c2bdaf9c1657530dd77d447 Mon Sep 17 00:00:00 2001 From: Jeff Thomas Date: Sun, 2 Mar 2025 21:45:23 +0100 Subject: [PATCH 01/12] Removed 'patternFlags' @PluginAttribute from RegexFilter @PluginFactory createFilter. (#3086) 8d05a7 --- .../log4j/core/filter/RegexFilter.java | 91 +++++++++++-------- ...remove_patternflags_from_PluginFactory.xml | 10 ++ 2 files changed, 63 insertions(+), 38 deletions(-) create mode 100644 src/changelog/2.25.0/3086_change_RegexFilter_remove_patternflags_from_PluginFactory.xml diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java index 400bd42e01e..52db17e8c3a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java @@ -16,9 +16,6 @@ */ package org.apache.logging.log4j.core.filter; -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.Comparator; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.logging.log4j.Level; @@ -26,6 +23,10 @@ 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.message.Message; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.plugins.Configurable; @@ -45,7 +46,6 @@ @Plugin public final class RegexFilter extends AbstractFilter { - private static final int DEFAULT_PATTERN_FLAGS = 0; private final Pattern pattern; private final boolean useRawMessage; @@ -101,10 +101,7 @@ private Result filter(final String msg) { @Override public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("useRaw=").append(useRawMessage); - sb.append(", pattern=").append(pattern.toString()); - return sb.toString(); + return "useRaw=" + useRawMessage + ", pattern=" + pattern.toString(); } /** @@ -114,6 +111,7 @@ public String toString() { * The regular expression to match. * @param patternFlags * An array of Strings where each String is a {@link Pattern#compile(String, int)} compilation flag. + * (no longer used - pattern flags can be embedded in regex-expression. * @param useRawMsg * If true, the raw message will be used, otherwise the formatted message will be used. * @param onMatch @@ -121,47 +119,64 @@ public String toString() { * @param onMismatch * The action to perform when a mismatch occurs. * @return The RegexFilter. - * @throws IllegalAccessException - * @throws IllegalArgumentException + * @throws IllegalAccessException When there is no access to the definition of the specified member. + * @throws IllegalArgumentException When passed an illegal or inappropriate argument. + * @deprecated use {@link #createFilter(String, Boolean, Result, Result)} + */ + @Deprecated + // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder + public static RegexFilter createFilter( + // @formatter:off + @PluginAttribute("regex") final String regex, + final String[] patternFlags, + @PluginAttribute("useRawMsg") final Boolean useRawMsg, + @PluginAttribute("onMatch") final Result match, + @PluginAttribute("onMismatch") final Result mismatch) + // @formatter:on + throws IllegalArgumentException, IllegalAccessException { + + // LOG4J-3086 - pattern-flags can be embedded in RegEx expression + + return createFilter(regex, useRawMsg, match, mismatch); + } + + /** + * Creates a Filter that matches a regular expression. + * + * @param regex + * The regular expression to match. + * @param useRawMsg + * If {@code true}, for {@link ParameterizedMessage}, {@link StringFormattedMessage}, and {@link MessageFormatMessage}, the message format pattern; for {@link StructuredDataMessage}, the message field will be used as the match target. + * @param match + * The action to perform when a match occurs. + * @param mismatch + * The action to perform when a mismatch occurs. + * @return The RegexFilter. + * @throws IllegalAccessException When there is no access to the definition of the specified member. + * @throws IllegalArgumentException When passed an illegal or inappropriate argument. */ // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder @PluginFactory public static RegexFilter createFilter( // @formatter:off - @PluginAttribute final String regex, - @PluginElement final String[] patternFlags, - @PluginAttribute final Boolean useRawMsg, - @PluginAttribute final Result onMatch, - @PluginAttribute final Result onMismatch) + @PluginAttribute("regex") final String regex, + @PluginAttribute("useRawMsg") final Boolean useRawMsg, + @PluginAttribute("onMatch") final Result match, + @PluginAttribute("onMismatch") final Result mismatch) // @formatter:on throws IllegalArgumentException, IllegalAccessException { + boolean raw = Boolean.TRUE.equals(useRawMsg); if (regex == null) { LOGGER.error("A regular expression must be provided for RegexFilter"); return null; } - return new RegexFilter(useRawMsg, Pattern.compile(regex, toPatternFlags(patternFlags)), onMatch, onMismatch); - } - - private static int toPatternFlags(final String[] patternFlags) - throws IllegalArgumentException, IllegalAccessException { - if (patternFlags == null || patternFlags.length == 0) { - return DEFAULT_PATTERN_FLAGS; - } - final Field[] fields = Pattern.class.getDeclaredFields(); - final Comparator comparator = (f1, f2) -> f1.getName().compareTo(f2.getName()); - Arrays.sort(fields, comparator); - final String[] fieldNames = new String[fields.length]; - for (int i = 0; i < fields.length; i++) { - fieldNames[i] = fields[i].getName(); - } - int flags = DEFAULT_PATTERN_FLAGS; - for (final String test : patternFlags) { - final int index = Arrays.binarySearch(fieldNames, test); - if (index >= 0) { - final Field field = fields[index]; - flags |= field.getInt(Pattern.class); - } + final Pattern pattern; + try { + pattern = Pattern.compile(regex); + } catch (final Exception ex) { + LOGGER.error("Unable to compile regular expression: {}", regex, ex); + return null; } - return flags; + return new RegexFilter(raw, pattern, match, mismatch); } } diff --git a/src/changelog/2.25.0/3086_change_RegexFilter_remove_patternflags_from_PluginFactory.xml b/src/changelog/2.25.0/3086_change_RegexFilter_remove_patternflags_from_PluginFactory.xml new file mode 100644 index 00000000000..0e61653f85c --- /dev/null +++ b/src/changelog/2.25.0/3086_change_RegexFilter_remove_patternflags_from_PluginFactory.xml @@ -0,0 +1,10 @@ + + + + + Removed 'patternFlags' @PluginAttribute from RegexFilter @PluginFactory createFilter. + + From cdd9eed13f4add77a2fc063d65e3b7ba1330ae5d Mon Sep 17 00:00:00 2001 From: Jeff Thomas Date: Sun, 2 Mar 2025 21:48:05 +0100 Subject: [PATCH 02/12] Updates per PR Code Review (#3086) + made AbstractFiltter.AbstractFilterBuilder onMatch/onMismatch fields protected + added AbstractFilter(AbstractFilterBuilder) constructor + added RegexFilter.Builder implementation + added RegexFilter(Builder) constructor + moved RegexFilter Pattern compile into constructor + added fields to persist configuration propertties + getters (regexExpression, patternFlags) + changed private constructor to accept builder as argument + renamed private method 'targetMessageTest' to more approprriate 'getMessageTextByType' + added Javadoc + grouped deprecations --- .../log4j/core/filter/RegexFilterTest.java | 19 +- .../log4j/core/filter/AbstractFilter.java | 33 +- .../log4j/core/filter/RegexFilter.java | 355 ++++++++++++++---- .../logging/log4j/core/util/Builder.java | 9 +- ...remove_patternflags_from_PluginFactory.xml | 0 5 files changed, 342 insertions(+), 74 deletions(-) rename src/changelog/{2.25.0 => .3.x.x}/3086_change_RegexFilter_remove_patternflags_from_PluginFactory.xml (100%) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java index a3e8bf3d025..61ecdf83f31 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java @@ -18,6 +18,8 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -40,8 +42,19 @@ public static void before() { } @Test - public void testThresholds() throws Exception { - RegexFilter filter = RegexFilter.createFilter(".* test .*", null, false, null, null); + void testRegexFilterDoesNotThrowWithAllTheParametersExceptRegexEqualNull() { + assertDoesNotThrow(() -> { + RegexFilter.newBuilder().setRegex(".* test .*").build(); + }); + } + + @Test + void testThresholds() throws Exception { + RegexFilter filter = RegexFilter.newBuilder() + .setRegex(".* test .*") + .setUseRawMsg(false) + .build(); + assertNotNull(filter); filter.start(); assertTrue(filter.isStarted()); assertSame( @@ -59,7 +72,7 @@ public void testThresholds() throws Exception { .setMessage(new SimpleMessage("test")) // .build(); assertSame(Filter.Result.DENY, filter.filter(event)); - filter = RegexFilter.createFilter(null, null, false, null, null); + filter = RegexFilter.newBuilder().build(); assertNull(filter); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/AbstractFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/AbstractFilter.java index d9b3d1dbf78..4c76b65b018 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/AbstractFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/AbstractFilter.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.filter; +import java.util.Objects; +import java.util.Optional; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.core.AbstractLifeCycle; @@ -43,16 +45,30 @@ public abstract static class AbstractFilterBuilder builder) { + + Objects.requireNonNull(builder, "The 'builder' argument cannot be null."); + + this.onMatch = Optional.ofNullable(builder.onMatch).orElse(Result.NEUTRAL); + this.onMismatch = Optional.ofNullable(builder.onMismatch).orElse(Result.DENY); + } + @Override protected boolean equalsImpl(final Object obj) { if (this == obj) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java index 52db17e8c3a..cae5ba80b54 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java @@ -16,7 +16,10 @@ */ package org.apache.logging.log4j.core.filter; -import java.util.regex.Matcher; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Objects; import java.util.regex.Pattern; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; @@ -26,7 +29,9 @@ 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.config.plugins.PluginBuilderAttribute; +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; +import org.apache.logging.log4j.core.config.plugins.PluginElement; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.plugins.Configurable; @@ -46,137 +51,355 @@ @Plugin public final class RegexFilter extends AbstractFilter { + /** The regular-expression. */ + private final String regex; + + /** The pattern compiled from the regular-expression. */ private final Pattern pattern; + + /** Flag: if {@code true} use message format-pattern / field for the match target. */ private final boolean useRawMessage; - private RegexFilter(final boolean raw, final Pattern pattern, final Result onMatch, final Result onMismatch) { - super(onMatch, onMismatch); - this.pattern = pattern; - this.useRawMessage = raw; + /** + * Constructs a new {@code RegexFilter} configured by the given builder. + * @param builder the builder + * @throws IllegalArgumentException if the regular expression cannot be compiled to a pattern + */ + private RegexFilter(final Builder builder) { + + super(builder); + + this.regex = builder.regex; + this.useRawMessage = Boolean.TRUE.equals(builder.useRawMsg); + + try { + this.pattern = Pattern.compile(regex); + } catch (final Exception ex) { + throw new IllegalArgumentException("Unable to compile regular expression: '" + regex + "'.", ex); + } + } + + /** + * Returns the regular-expression. + * @return the regular-expression (it may be an empty string but never {@code null}) + */ + public String getRegex() { + return this.regex; } + /** + * Returns the compiled regular-expression pattern. + * @return the pattern (will never be {@code null} + */ + public Pattern getPattern() { + return this.pattern; + } + + /** + * Returns whether the raw-message should be used. + * @return {@code} if the raw message should be used; otherwise, {@code false} + */ + public boolean isUseRawMessage() { + return this.useRawMessage; + } + + /** {@inheritDoc} */ @Override public Result filter( final Logger logger, final Level level, final Marker marker, final String msg, final Object... params) { - if (useRawMessage || params == null || params.length == 0) { - return filter(msg); - } - return filter(ParameterizedMessage.format(msg, params)); + return (useRawMessage || params == null || params.length == 0) + ? filter(msg) + : filter(ParameterizedMessage.format(msg, params)); } + /** {@inheritDoc} */ @Override public Result filter( final Logger logger, final Level level, final Marker marker, final Object msg, final Throwable t) { - if (msg == null) { - return onMismatch; - } - return filter(msg.toString()); + return (msg == null) ? this.onMismatch : filter(msg.toString()); } + /** {@inheritDoc} */ @Override public Result filter( final Logger logger, final Level level, final Marker marker, final Message msg, final Throwable t) { if (msg == null) { return onMismatch; } - final String text = useRawMessage ? msg.getFormat() : msg.getFormattedMessage(); - return filter(text); + return filter(getMessageTextByType(msg)); } + /** {@inheritDoc} */ @Override public Result filter(final LogEvent event) { - final String text = useRawMessage - ? event.getMessage().getFormat() - : event.getMessage().getFormattedMessage(); - return filter(text); + return filter(getMessageTextByType(event.getMessage())); } + /** + * Apply the filter to the given message and return the match/mismatch result. + *

+ * If the given '{@code msg}' is {@code null} the configured mismatch result will be returned. + *

+ * @param msg the message + * @return the filter result + */ private Result filter(final String msg) { if (msg == null) { return onMismatch; } - final Matcher m = pattern.matcher(msg); - return m.matches() ? onMatch : onMismatch; + return pattern.matcher(msg).matches() ? onMatch : onMismatch; + } + + /** + * Tests the filter pattern against the given Log4j {@code Message}. + *

+ * If the raw-message flag is enabled and message is an instance of the following, the raw message format + * will be returned. + *

+ *
    + *
  • {@link MessageFormatMessage}
  • + *
  • {@link ParameterizedMessage}
  • + *
  • {@link StringFormattedMessage}
  • + *
  • {@link StructuredDataMessage}
  • + *
+ *

+ * If the '{@code useRawMessage}' flag is disabled OR the message is not one of the above + * implementations, the message's formatted message will be returned. + *

+ *

Developer Note

+ *

+ * While `Message#getFormat()` is broken in general, it still makes sense for certain types. + * Hence, suppress the deprecation warning. + *

+ * + * @param message the message + * @return the target message based on configuration and message-type + */ + @SuppressWarnings("deprecation") + private String getMessageTextByType(final Message message) { + return useRawMessage + && (message instanceof ParameterizedMessage + || message instanceof StringFormattedMessage + || message instanceof MessageFormatMessage + || message instanceof StructuredDataMessage) + ? message.getFormat() + : message.getFormattedMessage(); } @Override public String toString() { - return "useRaw=" + useRawMessage + ", pattern=" + pattern.toString(); + return "useRawMessage=" + useRawMessage + ", regex=" + regex + ", pattern=" + pattern.toString(); } /** - * Creates a Filter that matches a regular expression. + * Creates a new builder instance. * - * @param regex - * The regular expression to match. - * @param patternFlags - * An array of Strings where each String is a {@link Pattern#compile(String, int)} compilation flag. - * (no longer used - pattern flags can be embedded in regex-expression. - * @param useRawMsg - * If true, the raw message will be used, otherwise the formatted message will be used. - * @param onMatch - * The action to perform when a match occurs. - * @param onMismatch - * The action to perform when a mismatch occurs. - * @return The RegexFilter. - * @throws IllegalAccessException When there is no access to the definition of the specified member. - * @throws IllegalArgumentException When passed an illegal or inappropriate argument. - * @deprecated use {@link #createFilter(String, Boolean, Result, Result)} + * @return the new builder instance + */ + @PluginBuilderFactory + public static RegexFilter.Builder newBuilder() { + return new RegexFilter.Builder(); + } + + /** + * A {@link RegexFilter} builder instance. + */ + public static final class Builder extends AbstractFilterBuilder + implements org.apache.logging.log4j.core.util.Builder { + + /* NOTE: LOG4J-3086 - No patternFlags in builder - this functionality has been deprecated/removed. */ + + /** + * The regular expression to match. + */ + @PluginBuilderAttribute + private String regex; + + /** + * If {@code true}, for {@link ParameterizedMessage}, {@link StringFormattedMessage}, + * and {@link MessageFormatMessage}, the message format pattern; for {@link StructuredDataMessage}, + * the message field will be used as the match target. + */ + @PluginBuilderAttribute + private Boolean useRawMsg; + + /** + * Private constructor. + */ + private Builder() { + super(); + } + + /** + * Sets the regular-expression. + * + * @param regex the regular-expression + * @return this builder + */ + public Builder setRegex(final String regex) { + this.regex = regex; + return this; + } + + /** + * Sets the use raw msg flag. + * + * @param useRawMsg {@code true} if the message format-patter/field will be used as match target; + * otherwise, {@code false} + * @return this builder + */ + public Builder setUseRawMsg(final boolean useRawMsg) { + this.useRawMsg = useRawMsg; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isValid() { + return (regex != null); + } + + /** + * Builds and returns a {@link RegexFilter} instance configured by this builder. + * + * @return the created {@link RegexFilter} or {@code null} if the builder is misconfigured + */ + @Override + public RegexFilter build() { + + if (!isValid()) { + return null; + } + + try { + return new RegexFilter(this); + } catch (final Exception ex) { + LOGGER.error("Unable to create RegexFilter. {}", ex.getMessage(), ex); + return null; + } + } + } + + /* + * DEPRECATIONS: + * The constructor/fields/methods below have been deprecated. + * - the 'create***' factory methods should no longer be used - use the builder instead + * - pattern-flags should now be passed via the regular expression itself + */ + + /** + * @deprecated pattern flags have been deprecated - they can just be included in the regex-expression. */ @Deprecated - // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder - public static RegexFilter createFilter( - // @formatter:off - @PluginAttribute("regex") final String regex, - final String[] patternFlags, - @PluginAttribute("useRawMsg") final Boolean useRawMsg, - @PluginAttribute("onMatch") final Result match, - @PluginAttribute("onMismatch") final Result mismatch) - // @formatter:on - throws IllegalArgumentException, IllegalAccessException { + private static final int DEFAULT_PATTERN_FLAGS = 0; - // LOG4J-3086 - pattern-flags can be embedded in RegEx expression + /** + * @deprecated - pattern flags no longer supported. + */ + @Deprecated + private String[] patternFlags = new String[0]; + + /** + * @deprecated use {@link RegexFilter.Builder} instead + */ + @Deprecated + @SuppressWarnings("MagicConstant") + private RegexFilter( + final boolean useRawMessage, + final String regex, + final String[] patternFlags, + final Result onMatch, + final Result onMismatch) { + super(onMatch, onMismatch); + this.regex = Objects.requireNonNull(regex, "The 'regex' argument must be provided for RegexFilter"); + this.patternFlags = patternFlags == null ? new String[0] : patternFlags.clone(); + try { + int flags = toPatternFlags(this.patternFlags); + this.pattern = Pattern.compile(regex, flags); + } catch (final Exception ex) { + throw new IllegalArgumentException("Unable to compile regular expression: '" + regex + "'.", ex); + } + this.useRawMessage = useRawMessage; + } - return createFilter(regex, useRawMsg, match, mismatch); + /** + * Returns the pattern-flags applied to the regular-expression when compiling the pattern. + * + * @return the pattern-flags (maybe empty but never {@code null} + * @deprecated pattern-flags are no longer supported + */ + @Deprecated + public String[] getPatternFlags() { + return this.patternFlags.clone(); } /** * Creates a Filter that matches a regular expression. * - * @param regex - * The regular expression to match. - * @param useRawMsg - * If {@code true}, for {@link ParameterizedMessage}, {@link StringFormattedMessage}, and {@link MessageFormatMessage}, the message format pattern; for {@link StructuredDataMessage}, the message field will be used as the match target. - * @param match - * The action to perform when a match occurs. - * @param mismatch - * The action to perform when a mismatch occurs. + * @param regex The regular expression to match. + * @param patternFlags An array of Strings where each String is a {@link Pattern#compile(String, int)} compilation flag. + * (no longer used - pattern flags can be embedded in regex-expression. + * @param useRawMsg If {@code true}, for {@link ParameterizedMessage}, {@link StringFormattedMessage}, + * and {@link MessageFormatMessage}, the message format pattern; for {@link StructuredDataMessage}, + * the message field will be used as the match target. + * @param match The action to perform when a match occurs. + * @param mismatch The action to perform when a mismatch occurs. * @return The RegexFilter. - * @throws IllegalAccessException When there is no access to the definition of the specified member. + * @throws IllegalAccessException When there is no access to the definition of the specified member. * @throws IllegalArgumentException When passed an illegal or inappropriate argument. + * @deprecated use {@link #newBuilder} to instantiate builder */ - // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder - @PluginFactory + @Deprecated public static RegexFilter createFilter( // @formatter:off @PluginAttribute("regex") final String regex, + @PluginElement("PatternFlags") final String[] patternFlags, @PluginAttribute("useRawMsg") final Boolean useRawMsg, @PluginAttribute("onMatch") final Result match, @PluginAttribute("onMismatch") final Result mismatch) // @formatter:on throws IllegalArgumentException, IllegalAccessException { + + // LOG4J-3086 - pattern-flags can be embedded in RegEx expression + boolean raw = Boolean.TRUE.equals(useRawMsg); if (regex == null) { LOGGER.error("A regular expression must be provided for RegexFilter"); return null; } - final Pattern pattern; + try { - pattern = Pattern.compile(regex); + return new RegexFilter(raw, regex, patternFlags, match, mismatch); } catch (final Exception ex) { - LOGGER.error("Unable to compile regular expression: {}", regex, ex); + LOGGER.error("Unable to create RegexFilter. {}", ex.getMessage(), ex); return null; } - return new RegexFilter(raw, pattern, match, mismatch); + } + + /** @deprecated pattern flags have been deprecated - they can just be included in the regex-expression. */ + @Deprecated + private static int toPatternFlags(final String[] patternFlags) + throws IllegalArgumentException, IllegalAccessException { + if (patternFlags == null || patternFlags.length == 0) { + return DEFAULT_PATTERN_FLAGS; + } + final Field[] fields = Pattern.class.getDeclaredFields(); + final Comparator comparator = (f1, f2) -> f1.getName().compareTo(f2.getName()); + Arrays.sort(fields, comparator); + final String[] fieldNames = new String[fields.length]; + for (int i = 0; i < fields.length; i++) { + fieldNames[i] = fields[i].getName(); + } + int flags = DEFAULT_PATTERN_FLAGS; + for (final String test : patternFlags) { + final int index = Arrays.binarySearch(fieldNames, test); + if (index >= 0) { + final Field field = fields[index]; + flags |= field.getInt(Pattern.class); + } + } + return flags; } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java index e99250edcc2..7d3f9bf65eb 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java @@ -45,8 +45,11 @@ public interface Builder extends Supplier { */ T build(); - @Override - default T get() { - return build(); + /** + * Validates that the builder is properly configured to build. + * @return {@code true} if the builder configuration is valid; otherwise, {@code false} + */ + default boolean isValid() { + return PluginBuilder.validateFields(this, getErrorPrefix()); } } diff --git a/src/changelog/2.25.0/3086_change_RegexFilter_remove_patternflags_from_PluginFactory.xml b/src/changelog/.3.x.x/3086_change_RegexFilter_remove_patternflags_from_PluginFactory.xml similarity index 100% rename from src/changelog/2.25.0/3086_change_RegexFilter_remove_patternflags_from_PluginFactory.xml rename to src/changelog/.3.x.x/3086_change_RegexFilter_remove_patternflags_from_PluginFactory.xml From 3827a0c6d47eaf6e5a47ffa863828813a25d05ad Mon Sep 17 00:00:00 2001 From: Jeff Thomas Date: Sun, 2 Mar 2025 21:48:39 +0100 Subject: [PATCH 03/12] A few more improvements + added tests (#3086) --- .../log4j/core/filter/RegexFilterTest.java | 126 +++++++++++++++--- .../log4j/core/filter/RegexFilter.java | 42 ++++-- 2 files changed, 142 insertions(+), 26 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java index 61ecdf83f31..c5a1373332e 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java @@ -19,9 +19,12 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import org.apache.logging.log4j.Level; @@ -89,9 +92,18 @@ public void testDotAllPattern() throws Exception { } @Test - public void testNoMsg() throws Exception { - final RegexFilter filter = RegexFilter.createFilter(".* test .*", null, false, null, null); + void testNoMsg() { + + final RegexFilter filter = + RegexFilter.newBuilder() + .setRegex(".* test .*") + .setUseRawMsg(false) + .build(); + + assertNotNull(filter); + filter.start(); + assertTrue(filter.isStarted()); assertSame(Filter.Result.DENY, filter.filter(null, Level.DEBUG, null, (Object) null, (Throwable) null)); assertSame(Filter.Result.DENY, filter.filter(null, Level.DEBUG, null, (Message) null, (Throwable) null)); @@ -99,28 +111,112 @@ public void testNoMsg() throws Exception { } @Test - public void testParameterizedMsg() throws Exception { + void testParameterizedMsg() { final String msg = "params {} {}"; final Object[] params = {"foo", "bar"}; // match against raw message - final RegexFilter rawFilter = RegexFilter.createFilter( - "params \\{\\} \\{\\}", - null, - true, // useRawMsg - Result.ACCEPT, - Result.DENY); + final RegexFilter rawFilter = + RegexFilter.newBuilder() + .setRegex("params \\{\\} \\{\\}") + .setUseRawMsg(true) + .setOnMatch(Result.ACCEPT) + .setOnMismatch(Result.DENY) + .build(); + + assertNotNull(rawFilter); + final Result rawResult = rawFilter.filter(null, null, null, msg, params); assertThat(rawResult, equalTo(Result.ACCEPT)); // match against formatted message - final RegexFilter fmtFilter = RegexFilter.createFilter( - "params foo bar", - null, - false, // useRawMsg - Result.ACCEPT, - Result.DENY); + final RegexFilter fmtFilter = + RegexFilter.newBuilder() + .setRegex("params foo bar") + .setUseRawMsg(false) + .setOnMatch(Result.ACCEPT) + .setOnMismatch(Result.DENY).build(); + + assertNotNull(fmtFilter); + final Result fmtResult = fmtFilter.filter(null, null, null, msg, params); assertThat(fmtResult, equalTo(Result.ACCEPT)); } + + /** + * A builder with no 'regex' expression should both be invalid and return null on 'build()'. + */ + @Test + void testWithValidRegex() { + + final String regex = "^[a-zA-Z0-9_]+$"; // matches alphanumeric with underscores + + final RegexFilter.Builder builder = + RegexFilter.newBuilder().setRegex(regex).setUseRawMsg(false).setOnMatch(Result.ACCEPT).setOnMismatch(Result.DENY); + + assertTrue(builder.isValid()); + + final RegexFilter filter = builder.build(); + + assertNotNull(filter); + + assertEquals(Result.ACCEPT, filter.filter("Hello_123")); + + assertEquals(Result.DENY, filter.filter("Hello@123")); + + assertEquals(regex, filter.getRegex()); + } + + @Test + void testRegexFilterGetters() { + + final String regex = "^[a-zA-Z0-9_]+$"; // matches alphanumeric with underscores + + final RegexFilter filter = + RegexFilter.newBuilder() + .setRegex(regex) + .setUseRawMsg(false) + .setOnMatch(Result.ACCEPT) + .setOnMismatch(Result.DENY) + .build(); + + assertNotNull(filter); + + assertEquals(regex, filter.getRegex()); + assertFalse(filter.isUseRawMessage()); + assertEquals(Result.ACCEPT, filter.getOnMatch()); + assertEquals(Result.DENY, filter.getOnMismatch()); + assertNotNull(filter.getPattern()); + assertEquals(regex, filter.getPattern().pattern()); + } + + /** + * A builder with no 'regex' expression should both be invalid and return null on 'build()'. + */ + @Test + void testBuilderWithoutRegexNotValid() { + + final RegexFilter.Builder builder = RegexFilter.newBuilder(); + + assertFalse(builder.isValid()); + + assertNull(builder.build()); + + } + + /** + * A builder with an invalid 'regex' expression should return null on 'build()'. + */ + @Test + void testBuilderWithInvalidRegexNotValid() { + + final RegexFilter.Builder builder = RegexFilter.newBuilder(); + + builder.setRegex("[a-z"); + + assertFalse(builder.isValid()); + + assertNull(builder.build()); + + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java index cae5ba80b54..fc9ea1a4511 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java @@ -21,6 +21,7 @@ import java.util.Comparator; import java.util.Objects; import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.core.Filter; @@ -51,9 +52,6 @@ @Plugin public final class RegexFilter extends AbstractFilter { - /** The regular-expression. */ - private final String regex; - /** The pattern compiled from the regular-expression. */ private final Pattern pattern; @@ -69,13 +67,12 @@ private RegexFilter(final Builder builder) { super(builder); - this.regex = builder.regex; this.useRawMessage = Boolean.TRUE.equals(builder.useRawMsg); try { - this.pattern = Pattern.compile(regex); + this.pattern = Pattern.compile(builder.regex); } catch (final Exception ex) { - throw new IllegalArgumentException("Unable to compile regular expression: '" + regex + "'.", ex); + throw new IllegalArgumentException("Unable to compile regular expression: '" + builder.regex + "'.", ex); } } @@ -84,7 +81,7 @@ private RegexFilter(final Builder builder) { * @return the regular-expression (it may be an empty string but never {@code null}) */ public String getRegex() { - return this.regex; + return this.pattern.pattern(); } /** @@ -143,7 +140,7 @@ public Result filter(final LogEvent event) { * @param msg the message * @return the filter result */ - private Result filter(final String msg) { + public Result filter(final String msg) { if (msg == null) { return onMismatch; } @@ -188,7 +185,7 @@ private String getMessageTextByType(final Message message) { @Override public String toString() { - return "useRawMessage=" + useRawMessage + ", regex=" + regex + ", pattern=" + pattern.toString(); + return "useRawMessage=" + useRawMessage + ", pattern=" + pattern.toString(); } /** @@ -258,7 +255,11 @@ public Builder setUseRawMsg(final boolean useRawMsg) { */ @Override public boolean isValid() { - return (regex != null); + boolean valid = true; + if (!isRegexValid()) { + valid = false; + } + return valid; } /** @@ -280,6 +281,25 @@ public RegexFilter build() { return null; } } + + /** + * Validates the 'regex' attribute. + *

+ * If the regular-expression is not set, or cannot be compiled to a valid pattern the validation will fail. + *

+ * @return {@code true} if the regular-expression is valid; otherwise, {@code false} + */ + private boolean isRegexValid() { + if (regex == null) { + return false; + } + try { + Pattern.compile(regex); + } catch (final PatternSyntaxException ex) { + return false; + } + return true; + } } /* @@ -313,7 +333,7 @@ private RegexFilter( final Result onMatch, final Result onMismatch) { super(onMatch, onMismatch); - this.regex = Objects.requireNonNull(regex, "The 'regex' argument must be provided for RegexFilter"); + Objects.requireNonNull(regex, "The 'regex' argument must be provided for RegexFilter"); this.patternFlags = patternFlags == null ? new String[0] : patternFlags.clone(); try { int flags = toPatternFlags(this.patternFlags); From 4d60384c2752c955ff64d916312556b90687080d Mon Sep 17 00:00:00 2001 From: Jeff Thomas Date: Sun, 2 Mar 2025 21:49:50 +0100 Subject: [PATCH 04/12] Fix validation behavior in RegexFilter (#3086) + added validation checks to RegexFilter + added JVerify nullability annotations to RegexFilter + updated javadoc + replaced deprecated usages of CompositeFilter#getFilters with CompositeFilter#getFiltersArray in AbstractFilterableTest --- .../log4j/core/filter/AbstractFilterTest.java | 1 - .../core/filter/AbstractFilterableTest.java | 20 +- .../log4j/core/filter/RegexFilterTest.java | 57 ++--- .../log4j/core/filter/RegexFilter.java | 231 ++++++++++-------- 4 files changed, 160 insertions(+), 149 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/AbstractFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/AbstractFilterTest.java index 34f0f7e6967..9bb1aabaecd 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/AbstractFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/AbstractFilterTest.java @@ -34,7 +34,6 @@ public class AbstractFilterTest { @Test public void testUnrolledBackwardsCompatible() { final ConcreteFilter filter = new ConcreteFilter(); - final Filter.Result expected = Filter.Result.DENY; verifyMethodsWithUnrolledVarargs(filter, Filter.Result.DENY); filter.testResult = Filter.Result.ACCEPT; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/AbstractFilterableTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/AbstractFilterableTest.java index 2bd3e95deb0..10a3327de0f 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/AbstractFilterableTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/AbstractFilterableTest.java @@ -53,7 +53,7 @@ public void testAddMultipleSimpleFilters() throws Exception { // adding a second filter converts the filter // into a CompositeFilter.class filterable.addFilter(filter); - assertTrue(filterable.getFilter() instanceof CompositeFilter); + assertInstanceOf(CompositeFilter.class, filterable.getFilter()); assertEquals(2, ((CompositeFilter) filterable.getFilter()).getFiltersArray().length); } @@ -66,7 +66,7 @@ public void testAddMultipleEqualSimpleFilter() throws Exception { // adding a second filter converts the filter // into a CompositeFilter.class filterable.addFilter(filter); - assertTrue(filterable.getFilter() instanceof CompositeFilter); + assertInstanceOf(CompositeFilter.class, filterable.getFilter()); assertEquals(2, ((CompositeFilter) filterable.getFilter()).getFiltersArray().length); } @@ -92,7 +92,7 @@ public void testAddMultipleCompositeFilters() throws Exception { // adding a second filter converts the filter // into a CompositeFilter.class filterable.addFilter(compositeFilter); - assertTrue(filterable.getFilter() instanceof CompositeFilter); + assertInstanceOf(CompositeFilter.class, filterable.getFilter()); assertEquals(6, ((CompositeFilter) filterable.getFilter()).getFiltersArray().length); } @@ -108,7 +108,7 @@ public void testAddSimpleFilterAndCompositeFilter() throws Exception { // adding a second filter converts the filter // into a CompositeFilter.class filterable.addFilter(compositeFilter); - assertTrue(filterable.getFilter() instanceof CompositeFilter); + assertInstanceOf(CompositeFilter.class, filterable.getFilter()); assertEquals(2, ((CompositeFilter) filterable.getFilter()).getFiltersArray().length); } @@ -124,7 +124,7 @@ public void testAddCompositeFilterAndSimpleFilter() throws Exception { // adding a second filter converts the filter // into a CompositeFilter.class filterable.addFilter(notInCompositeFilterFilter); - assertTrue(filterable.getFilter() instanceof CompositeFilter); + assertInstanceOf(CompositeFilter.class, filterable.getFilter()); assertEquals(3, ((CompositeFilter) filterable.getFilter()).getFiltersArray().length); } @@ -169,7 +169,7 @@ public void testRemoveSimpleEqualFilterFromMultipleSimpleFilters() throws Except filterable.addFilter(filterOriginal); filterable.addFilter(filterCopy); filterable.removeFilter(filterCopy); - assertTrue(filterable.getFilter() instanceof CompositeFilter); + assertInstanceOf(CompositeFilter.class, filterable.getFilter()); assertEquals(2, ((CompositeFilter) filterable.getFilter()).getFiltersArray().length); filterable.removeFilter(filterCopy); assertEquals(filterOriginal, filterable.getFilter()); @@ -223,7 +223,7 @@ public void testRemoveSimpleFilterFromCompositeAndSimpleFilter() { // should not remove internal filter of compositeFilter filterable.removeFilter(anotherFilter); - assertTrue(filterable.getFilter() instanceof CompositeFilter); + assertInstanceOf(CompositeFilter.class, filterable.getFilter()); assertEquals(2, ((CompositeFilter) filterable.getFilter()).getFiltersArray().length); } @@ -274,11 +274,7 @@ public boolean equals(final Object o) { final EqualFilter that = (EqualFilter) o; - if (key != null ? !key.equals(that.key) : that.key != null) { - return false; - } - - return true; + return key != null ? key.equals(that.key) : that.key == null; } @Override diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java index c5a1373332e..23c1796f13d 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java @@ -24,7 +24,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import org.apache.logging.log4j.Level; @@ -94,11 +93,10 @@ public void testDotAllPattern() throws Exception { @Test void testNoMsg() { - final RegexFilter filter = - RegexFilter.newBuilder() - .setRegex(".* test .*") - .setUseRawMsg(false) - .build(); + final RegexFilter filter = RegexFilter.newBuilder() + .setRegex(".* test .*") + .setUseRawMsg(false) + .build(); assertNotNull(filter); @@ -116,13 +114,12 @@ void testParameterizedMsg() { final Object[] params = {"foo", "bar"}; // match against raw message - final RegexFilter rawFilter = - RegexFilter.newBuilder() - .setRegex("params \\{\\} \\{\\}") - .setUseRawMsg(true) - .setOnMatch(Result.ACCEPT) - .setOnMismatch(Result.DENY) - .build(); + final RegexFilter rawFilter = RegexFilter.newBuilder() + .setRegex("params \\{\\} \\{\\}") + .setUseRawMsg(true) + .setOnMatch(Result.ACCEPT) + .setOnMismatch(Result.DENY) + .build(); assertNotNull(rawFilter); @@ -130,12 +127,12 @@ void testParameterizedMsg() { assertThat(rawResult, equalTo(Result.ACCEPT)); // match against formatted message - final RegexFilter fmtFilter = - RegexFilter.newBuilder() - .setRegex("params foo bar") - .setUseRawMsg(false) - .setOnMatch(Result.ACCEPT) - .setOnMismatch(Result.DENY).build(); + final RegexFilter fmtFilter = RegexFilter.newBuilder() + .setRegex("params foo bar") + .setUseRawMsg(false) + .setOnMatch(Result.ACCEPT) + .setOnMismatch(Result.DENY) + .build(); assertNotNull(fmtFilter); @@ -151,8 +148,11 @@ void testWithValidRegex() { final String regex = "^[a-zA-Z0-9_]+$"; // matches alphanumeric with underscores - final RegexFilter.Builder builder = - RegexFilter.newBuilder().setRegex(regex).setUseRawMsg(false).setOnMatch(Result.ACCEPT).setOnMismatch(Result.DENY); + final RegexFilter.Builder builder = RegexFilter.newBuilder() + .setRegex(regex) + .setUseRawMsg(false) + .setOnMatch(Result.ACCEPT) + .setOnMismatch(Result.DENY); assertTrue(builder.isValid()); @@ -172,13 +172,12 @@ void testRegexFilterGetters() { final String regex = "^[a-zA-Z0-9_]+$"; // matches alphanumeric with underscores - final RegexFilter filter = - RegexFilter.newBuilder() - .setRegex(regex) - .setUseRawMsg(false) - .setOnMatch(Result.ACCEPT) - .setOnMismatch(Result.DENY) - .build(); + final RegexFilter filter = RegexFilter.newBuilder() + .setRegex(regex) + .setUseRawMsg(false) + .setOnMatch(Result.ACCEPT) + .setOnMismatch(Result.DENY) + .build(); assertNotNull(filter); @@ -201,7 +200,6 @@ void testBuilderWithoutRegexNotValid() { assertFalse(builder.isValid()); assertNull(builder.build()); - } /** @@ -217,6 +215,5 @@ void testBuilderWithInvalidRegexNotValid() { assertFalse(builder.isValid()); assertNull(builder.build()); - } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java index fc9ea1a4511..a04ac76324d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java @@ -21,7 +21,6 @@ import java.util.Comparator; import java.util.Objects; import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.core.Filter; @@ -33,23 +32,22 @@ import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; import org.apache.logging.log4j.core.config.plugins.PluginElement; +import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; +import org.apache.logging.log4j.core.util.Assert; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.ParameterizedMessage; -import org.apache.logging.log4j.plugins.Configurable; -import org.apache.logging.log4j.plugins.Plugin; -import org.apache.logging.log4j.plugins.PluginAttribute; -import org.apache.logging.log4j.plugins.PluginElement; -import org.apache.logging.log4j.plugins.PluginFactory; +import org.apache.logging.log4j.message.StringFormattedMessage; +import org.apache.logging.log4j.message.StructuredDataMessage; +import org.apache.logging.log4j.util.Strings; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** - * This filter returns the onMatch result if the message matches the regular expression. - * - * The "useRawMsg" attribute can be used to indicate whether the regular expression should be applied to the result of - * calling Message.getMessageFormat (true) or Message.getFormattedMessage() (false). The default is false. - * + * This filter returns the {@code onMatch} result if the message exactly matches the configured + * "{@code regex}" regular-expression pattern; otherwise, it returns the {@code onMismatch} result. */ -@Configurable(elementType = Filter.ELEMENT_TYPE, printObject = true) -@Plugin +@Plugin(name = "RegexFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true) +@NullMarked public final class RegexFilter extends AbstractFilter { /** The pattern compiled from the regular-expression. */ @@ -61,12 +59,16 @@ public final class RegexFilter extends AbstractFilter { /** * Constructs a new {@code RegexFilter} configured by the given builder. * @param builder the builder - * @throws IllegalArgumentException if the regular expression cannot be compiled to a pattern + * @throws IllegalArgumentException if the regular expression is not configured or cannot be compiled to a pattern */ private RegexFilter(final Builder builder) { super(builder); + if (Strings.isNotBlank(builder.regex)) { + throw new IllegalArgumentException("The 'regex' attribute must not be null or empty."); + } + this.useRawMessage = Boolean.TRUE.equals(builder.useRawMsg); try { @@ -76,14 +78,6 @@ private RegexFilter(final Builder builder) { } } - /** - * Returns the regular-expression. - * @return the regular-expression (it may be an empty string but never {@code null}) - */ - public String getRegex() { - return this.pattern.pattern(); - } - /** * Returns the compiled regular-expression pattern. * @return the pattern (will never be {@code null} @@ -92,59 +86,123 @@ public Pattern getPattern() { return this.pattern; } + /** + * Returns the regular-expression. + * @return the regular-expression (it may be an empty string but never {@code null}) + */ + public String getRegex() { + return this.pattern.pattern(); + } + /** * Returns whether the raw-message should be used. - * @return {@code} if the raw message should be used; otherwise, {@code false} + * @return {@code true} if the raw message should be used; otherwise, {@code false} */ public boolean isUseRawMessage() { return this.useRawMessage; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + *

+ * This implementation performs the filter evaluation against the given message formatted with + * the given parameters. + *

+ *

+ * The following method arguments are ignored by this filter method implementation: + *

    + *
  • {@code logger}
  • + *
  • {@code level}
  • + *
  • {@code marker}
  • + *
+ *

+ */ @Override public Result filter( - final Logger logger, final Level level, final Marker marker, final String msg, final Object... params) { + final @Nullable Logger logger, + final @Nullable Level level, + final @Nullable Marker marker, + final @Nullable String msg, + final @Nullable Object @Nullable ... params) { + return (useRawMessage || params == null || params.length == 0) ? filter(msg) : filter(ParameterizedMessage.format(msg, params)); } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + *

+ * This implementation performs the filter evaluation against the given message. + *

+ *

+ * The following method arguments are ignored by this filter method implementation: + *

    + *
  • {@code logger}
  • + *
  • {@code level}
  • + *
  • {@code marker}
  • + *
  • {@code throwable}
  • + *
+ *

+ */ @Override public Result filter( - final Logger logger, final Level level, final Marker marker, final Object msg, final Throwable t) { - return (msg == null) ? this.onMismatch : filter(msg.toString()); + final @Nullable Logger logger, + final @Nullable Level level, + final @Nullable Marker marker, + final @Nullable Object message, + final @Nullable Throwable throwable) { + + return (message == null) ? this.onMismatch : filter(message.toString()); } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + *

+ * This implementation performs the filter evaluation against the given message. + *

+ *

+ * The following method arguments are ignored by this filter method implementation: + *

    + *
  • {@code logger}
  • + *
  • {@code level}
  • + *
  • {@code marker}
  • + *
  • {@code throwable}
  • + *
+ *

+ */ @Override public Result filter( - final Logger logger, final Level level, final Marker marker, final Message msg, final Throwable t) { - if (msg == null) { - return onMismatch; - } - return filter(getMessageTextByType(msg)); + final @Nullable Logger logger, + final @Nullable Level level, + final @Nullable Marker marker, + final @Nullable Message message, + final @Nullable Throwable throwable) { + return (message == null) ? this.onMismatch : filter(getMessageTextByType(message)); } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + * + * @throws NullPointerException if the {@code event} argument is {@code null} + */ @Override public Result filter(final LogEvent event) { + Objects.requireNonNull(event, "The 'event' argument must not be null."); return filter(getMessageTextByType(event.getMessage())); } /** - * Apply the filter to the given message and return the match/mismatch result. + * Apply the filter to the given message and return the {@code onMatch} result if the entire + * message matches the configured regex pattern; otherwise, {@code onMismatch}. *

- * If the given '{@code msg}' is {@code null} the configured mismatch result will be returned. + * If the given '{@code msg}' is {@code null} the configured {@code onMismatch} result will be returned. *

* @param msg the message - * @return the filter result + * @return the {@code onMatch} result if the pattern matches; otherwise, the {@code onMismatch} result */ - public Result filter(final String msg) { - if (msg == null) { - return onMismatch; - } - return pattern.matcher(msg).matches() ? onMatch : onMismatch; + public Result filter(final @Nullable String msg) { + return (msg != null && pattern.matcher(msg).matches()) ? onMatch : onMismatch; } /** @@ -183,6 +241,7 @@ private String getMessageTextByType(final Message message) { : message.getFormattedMessage(); } + /** {@inheritDoc} */ @Override public String toString() { return "useRawMessage=" + useRawMessage + ", pattern=" + pattern.toString(); @@ -190,12 +249,11 @@ public String toString() { /** * Creates a new builder instance. - * * @return the new builder instance */ @PluginBuilderFactory - public static RegexFilter.Builder newBuilder() { - return new RegexFilter.Builder(); + public static Builder newBuilder() { + return new Builder(); } /** @@ -210,7 +268,8 @@ public static final class Builder extends AbstractFilterBuilder - * If the regular-expression is not set, or cannot be compiled to a valid pattern the validation will fail. - *

- * @return {@code true} if the regular-expression is valid; otherwise, {@code false} - */ - private boolean isRegexValid() { - if (regex == null) { - return false; - } - try { - Pattern.compile(regex); - } catch (final PatternSyntaxException ex) { - return false; - } - return true; - } } /* @@ -327,11 +356,11 @@ private boolean isRegexValid() { @Deprecated @SuppressWarnings("MagicConstant") private RegexFilter( - final boolean useRawMessage, final String regex, - final String[] patternFlags, - final Result onMatch, - final Result onMismatch) { + final boolean useRawMessage, + final @Nullable String @Nullable [] patternFlags, + final @Nullable Result onMatch, + final @Nullable Result onMismatch) { super(onMatch, onMismatch); Objects.requireNonNull(regex, "The 'regex' argument must be provided for RegexFilter"); this.patternFlags = patternFlags == null ? new String[0] : patternFlags.clone(); @@ -375,32 +404,22 @@ public String[] getPatternFlags() { public static RegexFilter createFilter( // @formatter:off @PluginAttribute("regex") final String regex, - @PluginElement("PatternFlags") final String[] patternFlags, - @PluginAttribute("useRawMsg") final Boolean useRawMsg, - @PluginAttribute("onMatch") final Result match, - @PluginAttribute("onMismatch") final Result mismatch) + @PluginElement("PatternFlags") final String @Nullable [] patternFlags, + @PluginAttribute("useRawMsg") final @Nullable Boolean useRawMsg, + @PluginAttribute("onMatch") final @Nullable Result match, + @PluginAttribute("onMismatch") final @Nullable Result mismatch) // @formatter:on throws IllegalArgumentException, IllegalAccessException { // LOG4J-3086 - pattern-flags can be embedded in RegEx expression + Objects.requireNonNull(regex, "The 'regex' argument must not be null."); - boolean raw = Boolean.TRUE.equals(useRawMsg); - if (regex == null) { - LOGGER.error("A regular expression must be provided for RegexFilter"); - return null; - } - - try { - return new RegexFilter(raw, regex, patternFlags, match, mismatch); - } catch (final Exception ex) { - LOGGER.error("Unable to create RegexFilter. {}", ex.getMessage(), ex); - return null; - } + return new RegexFilter(regex, Boolean.TRUE.equals(useRawMsg), patternFlags, match, mismatch); } /** @deprecated pattern flags have been deprecated - they can just be included in the regex-expression. */ @Deprecated - private static int toPatternFlags(final String[] patternFlags) + private static int toPatternFlags(final String @Nullable [] patternFlags) throws IllegalArgumentException, IllegalAccessException { if (patternFlags == null || patternFlags.length == 0) { return DEFAULT_PATTERN_FLAGS; From aff317e48afab204abf80d286690c54486c6973c Mon Sep 17 00:00:00 2001 From: Jeff Thomas Date: Sun, 2 Mar 2025 19:49:09 +0100 Subject: [PATCH 05/12] Fixed a reverse logic check in a validation (#3086) --- .../log4j/core/config/CompositeConfigurationTest.java | 9 ++++----- .../apache/logging/log4j/core/filter/RegexFilter.java | 6 +++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java index de4d166524f..4b8cc3034e2 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java @@ -246,11 +246,10 @@ private AppenderRef getAppenderRef(final List appenderRefList, fina private void runTest(final LoggerContextRule rule, final Statement statement) { try { rule.apply( - statement, - Description.createTestDescription( - getClass(), - Thread.currentThread().getStackTrace()[1].getMethodName())) - .evaluate(); + statement, + Description.createTestDescription(getClass(), + Thread.currentThread().getStackTrace()[1].getMethodName())) + .evaluate(); } catch (final Throwable e) { Throwables.rethrow(e); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java index a04ac76324d..0b26608b163 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java @@ -65,7 +65,7 @@ private RegexFilter(final Builder builder) { super(builder); - if (Strings.isNotBlank(builder.regex)) { + if (Strings.isBlank(builder.regex)) { throw new IllegalArgumentException("The 'regex' attribute must not be null or empty."); } @@ -316,8 +316,8 @@ public Builder setUseRawMsg(final boolean useRawMsg) { public @Nullable RegexFilter build() { // validate the "regex" attribute - if (this.regex == null) { - LOGGER.error("Unable to create RegexFilter: The 'regex' attribute must be provided."); + if (Strings.isEmpty(this.regex)) { + LOGGER.error("Unable to create RegexFilter: The 'regex' attribute be set to a non-empty String."); return null; } From 20d541f8e716545bf5647a1432baa48999729207 Mon Sep 17 00:00:00 2001 From: Jeff Thomas Date: Sun, 2 Mar 2025 19:58:38 +0100 Subject: [PATCH 06/12] Fix Spotless errors (#3086) --- .../log4j/core/config/CompositeConfigurationTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java index 4b8cc3034e2..de4d166524f 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java @@ -246,10 +246,11 @@ private AppenderRef getAppenderRef(final List appenderRefList, fina private void runTest(final LoggerContextRule rule, final Statement statement) { try { rule.apply( - statement, - Description.createTestDescription(getClass(), - Thread.currentThread().getStackTrace()[1].getMethodName())) - .evaluate(); + statement, + Description.createTestDescription( + getClass(), + Thread.currentThread().getStackTrace()[1].getMethodName())) + .evaluate(); } catch (final Throwable e) { Throwables.rethrow(e); } From d289be39a0f4d8a50c32ccbf59be2854a75dbb06 Mon Sep 17 00:00:00 2001 From: Jeff Thomas Date: Sun, 2 Mar 2025 21:50:37 +0100 Subject: [PATCH 07/12] Fix RegexFilterTest (#3086) --- .../logging/log4j/core/filter/RegexFilterTest.java | 10 ++-------- .../apache/logging/log4j/core/filter/RegexFilter.java | 6 ++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java index 23c1796f13d..c4b45463c49 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java @@ -39,8 +39,8 @@ public class RegexFilterTest { @BeforeAll - public static void before() { - StatusLogger.getLogger().setLevel(Level.OFF); + static void before() { + StatusLogger.getLogger().getFallbackListener().setLevel(Level.OFF); } @Test @@ -154,8 +154,6 @@ void testWithValidRegex() { .setOnMatch(Result.ACCEPT) .setOnMismatch(Result.DENY); - assertTrue(builder.isValid()); - final RegexFilter filter = builder.build(); assertNotNull(filter); @@ -197,8 +195,6 @@ void testBuilderWithoutRegexNotValid() { final RegexFilter.Builder builder = RegexFilter.newBuilder(); - assertFalse(builder.isValid()); - assertNull(builder.build()); } @@ -212,8 +208,6 @@ void testBuilderWithInvalidRegexNotValid() { builder.setRegex("[a-z"); - assertFalse(builder.isValid()); - assertNull(builder.build()); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java index 0b26608b163..e37af4eba84 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java @@ -307,6 +307,12 @@ public Builder setUseRawMsg(final boolean useRawMsg) { return this; } + /** {@inheritDoc} */ + @Override + public boolean isValid() { + return (Strings.isNotEmpty(this.regex)); + } + /** * Builds and returns a {@link RegexFilter} instance configured by this builder. * From 0d348a67dc49b887db705f44bb5499e053da6bfb Mon Sep 17 00:00:00 2001 From: Jeff Thomas Date: Sun, 2 Mar 2025 22:49:17 +0100 Subject: [PATCH 08/12] Cleaned up cherry-pick from 2.x - removed deprecated API (#3086) --- .../log4j/core/filter/RegexFilterTest.java | 14 +- .../log4j/core/filter/RegexFilter.java | 153 +++--------------- 2 files changed, 24 insertions(+), 143 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java index c4b45463c49..8f46d891ddb 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java @@ -37,7 +37,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -public class RegexFilterTest { +class RegexFilterTest { @BeforeAll static void before() { StatusLogger.getLogger().getFallbackListener().setLevel(Level.OFF); @@ -78,18 +78,6 @@ void testThresholds() throws Exception { assertNull(filter); } - @Test - public void testDotAllPattern() throws Exception { - final String singleLine = "test single line matches"; - final String multiLine = "test multi line matches\nsome more lines"; - final RegexFilter filter = RegexFilter.createFilter( - ".*line.*", new String[] {"DOTALL", "COMMENTS"}, false, Filter.Result.DENY, Filter.Result.ACCEPT); - final Result singleLineResult = filter.filter(null, null, null, (Object) singleLine, (Throwable) null); - final Result multiLineResult = filter.filter(null, null, null, (Object) multiLine, (Throwable) null); - assertThat(singleLineResult, equalTo(Result.DENY)); - assertThat(multiLineResult, equalTo(Result.DENY)); - } - @Test void testNoMsg() { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java index e37af4eba84..33e7f9248ee 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java @@ -16,9 +16,6 @@ */ package org.apache.logging.log4j.core.filter; -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.Comparator; import java.util.Objects; import java.util.regex.Pattern; import org.apache.logging.log4j.Level; @@ -26,18 +23,16 @@ 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.PluginBuilderAttribute; -import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; -import org.apache.logging.log4j.core.config.plugins.PluginElement; -import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; -import org.apache.logging.log4j.core.util.Assert; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.message.StringFormattedMessage; import org.apache.logging.log4j.message.StructuredDataMessage; +import org.apache.logging.log4j.plugins.Configurable; +import org.apache.logging.log4j.plugins.Plugin; +import org.apache.logging.log4j.plugins.PluginBuilderAttribute; +import org.apache.logging.log4j.plugins.PluginFactory; +import org.apache.logging.log4j.plugins.util.Assert; +import org.apache.logging.log4j.plugins.validation.constraints.Required; import org.apache.logging.log4j.util.Strings; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -45,9 +40,15 @@ /** * This filter returns the {@code onMatch} result if the message exactly matches the configured * "{@code regex}" regular-expression pattern; otherwise, it returns the {@code onMismatch} result. + *

+ * The "useRawMsg" attribute can be used to indicate whether the regular expression should be applied to + * the result of calling Message.getMessageFormat (true) or Message.getFormattedMessage() (false). + * The default is {@code false}. + *

*/ -@Plugin(name = "RegexFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true) +@Configurable(elementType = Filter.ELEMENT_TYPE, printObject = true) @NullMarked +@Plugin public final class RegexFilter extends AbstractFilter { /** The pattern compiled from the regular-expression. */ @@ -65,6 +66,10 @@ private RegexFilter(final Builder builder) { super(builder); + // NOTE: the constructor throws exceptions but is only called from Builder#build() where *null* + // should be returned for a misconfigured builder. *If* an exception is thrown here + // it will be caught and logged in the builder and not propagated by returning *null*. + if (Strings.isBlank(builder.regex)) { throw new IllegalArgumentException("The 'regex' attribute must not be null or empty."); } @@ -128,6 +133,7 @@ public Result filter( return (useRawMessage || params == null || params.length == 0) ? filter(msg) : filter(ParameterizedMessage.format(msg, params)); + } /** @@ -212,7 +218,6 @@ public Result filter(final @Nullable String msg) { * will be returned. *

*
    - *
  • {@link MessageFormatMessage}
  • *
  • {@link ParameterizedMessage}
  • *
  • {@link StringFormattedMessage}
  • *
  • {@link StructuredDataMessage}
  • @@ -235,7 +240,6 @@ private String getMessageTextByType(final Message message) { return useRawMessage && (message instanceof ParameterizedMessage || message instanceof StringFormattedMessage - || message instanceof MessageFormatMessage || message instanceof StructuredDataMessage) ? message.getFormat() : message.getFormattedMessage(); @@ -244,14 +248,14 @@ private String getMessageTextByType(final Message message) { /** {@inheritDoc} */ @Override public String toString() { - return "useRawMessage=" + useRawMessage + ", pattern=" + pattern.toString(); + return "useRawMessage=" + useRawMessage + ", pattern=" + pattern; } /** * Creates a new builder instance. * @return the new builder instance */ - @PluginBuilderFactory + @PluginFactory public static Builder newBuilder() { return new Builder(); } @@ -260,7 +264,7 @@ public static Builder newBuilder() { * A {@link RegexFilter} builder instance. */ public static final class Builder extends AbstractFilterBuilder - implements org.apache.logging.log4j.core.util.Builder { + implements org.apache.logging.log4j.plugins.util.Builder { /* NOTE: LOG4J-3086 - No patternFlags in builder - this functionality has been deprecated/removed. */ @@ -272,8 +276,8 @@ public static final class Builder extends AbstractFilterBuilder comparator = (f1, f2) -> f1.getName().compareTo(f2.getName()); - Arrays.sort(fields, comparator); - final String[] fieldNames = new String[fields.length]; - for (int i = 0; i < fields.length; i++) { - fieldNames[i] = fields[i].getName(); - } - int flags = DEFAULT_PATTERN_FLAGS; - for (final String test : patternFlags) { - final int index = Arrays.binarySearch(fieldNames, test); - if (index >= 0) { - final Field field = fields[index]; - flags |= field.getInt(Pattern.class); - } - } - return flags; - } } From 5a0aee1feb84289dc9d7e1f7c4080d1c19dd5744 Mon Sep 17 00:00:00 2001 From: Jeff Thomas Date: Sun, 2 Mar 2025 23:23:38 +0100 Subject: [PATCH 09/12] Reverted cherry picked change to legacy Builder. (#3086) --- .../java/org/apache/logging/log4j/core/util/Builder.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java index 7d3f9bf65eb..e99250edcc2 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java @@ -45,11 +45,8 @@ public interface Builder extends Supplier { */ T build(); - /** - * Validates that the builder is properly configured to build. - * @return {@code true} if the builder configuration is valid; otherwise, {@code false} - */ - default boolean isValid() { - return PluginBuilder.validateFields(this, getErrorPrefix()); + @Override + default T get() { + return build(); } } From 2c35ef84cdc47d0994d5b0f3a021fb710e660f9e Mon Sep 17 00:00:00 2001 From: Jeff Thomas Date: Sun, 2 Mar 2025 23:25:05 +0100 Subject: [PATCH 10/12] Removed 'isValid()' from RegexFilter#Builder() - validation API has not yet been merged to main (#3086) --- .../org/apache/logging/log4j/core/filter/RegexFilter.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java index 33e7f9248ee..992ba03a059 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java @@ -133,7 +133,6 @@ public Result filter( return (useRawMessage || params == null || params.length == 0) ? filter(msg) : filter(ParameterizedMessage.format(msg, params)); - } /** @@ -311,11 +310,6 @@ public Builder setUseRawMsg(final boolean useRawMsg) { return this; } - /** {@inheritDoc} */ - public boolean isValid() { - return (Strings.isNotEmpty(this.regex)); - } - /** * Builds and returns a {@link RegexFilter} instance configured by this builder. * @@ -339,5 +333,4 @@ public boolean isValid() { } } } - } From 050567dd06d5b9b47f4c61712931862de3e48279 Mon Sep 17 00:00:00 2001 From: Jeff Thomas Date: Sun, 2 Mar 2025 23:26:20 +0100 Subject: [PATCH 11/12] Cleaned up AbstractFilterableTest to better match JUnit5 (#3086) --- .../core/filter/AbstractFilterableTest.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/AbstractFilterableTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/AbstractFilterableTest.java index 10a3327de0f..a320ae9fa20 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/AbstractFilterableTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/AbstractFilterableTest.java @@ -18,16 +18,16 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertTrue; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Filter; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class AbstractFilterableTest { +class AbstractFilterableTest { MockedAbstractFilterable filterable; @@ -37,7 +37,7 @@ public void setup() { } @Test - public void testAddSimpleFilter() throws Exception { + void testAddSimpleFilter() { final Filter filter = ThresholdFilter.createFilter(Level.ERROR, null, null); filterable.addFilter(filter); @@ -45,7 +45,7 @@ public void testAddSimpleFilter() throws Exception { } @Test - public void testAddMultipleSimpleFilters() throws Exception { + void testAddMultipleSimpleFilters() { final Filter filter = ThresholdFilter.createFilter(Level.ERROR, null, null); filterable.addFilter(filter); @@ -58,7 +58,7 @@ public void testAddMultipleSimpleFilters() throws Exception { } @Test - public void testAddMultipleEqualSimpleFilter() throws Exception { + void testAddMultipleEqualSimpleFilter() { final Filter filter = new EqualFilter("test"); filterable.addFilter(filter); @@ -71,7 +71,7 @@ public void testAddMultipleEqualSimpleFilter() throws Exception { } @Test - public void testAddCompositeFilter() throws Exception { + void testAddCompositeFilter() { final Filter filter1 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter filter2 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter compositeFilter = CompositeFilter.createFilters(new Filter[] {filter1, filter2}); @@ -81,7 +81,7 @@ public void testAddCompositeFilter() throws Exception { } @Test - public void testAddMultipleCompositeFilters() throws Exception { + void testAddMultipleCompositeFilters() { final Filter filter1 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter filter2 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter filter3 = ThresholdFilter.createFilter(Level.ERROR, null, null); @@ -97,7 +97,7 @@ public void testAddMultipleCompositeFilters() throws Exception { } @Test - public void testAddSimpleFilterAndCompositeFilter() throws Exception { + void testAddSimpleFilterAndCompositeFilter() { final Filter filter1 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter filter2 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter notInCompositeFilterFilter = ThresholdFilter.createFilter(Level.ERROR, null, null); @@ -113,7 +113,7 @@ public void testAddSimpleFilterAndCompositeFilter() throws Exception { } @Test - public void testAddCompositeFilterAndSimpleFilter() throws Exception { + void testAddCompositeFilterAndSimpleFilter() { final Filter filter1 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter filter2 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter notInCompositeFilterFilter = ThresholdFilter.createFilter(Level.ERROR, null, null); @@ -129,7 +129,7 @@ public void testAddCompositeFilterAndSimpleFilter() throws Exception { } @Test - public void testRemoveSimpleFilterFromSimpleFilter() throws Exception { + void testRemoveSimpleFilterFromSimpleFilter() { final Filter filter = ThresholdFilter.createFilter(Level.ERROR, null, null); filterable.addFilter(filter); @@ -138,7 +138,7 @@ public void testRemoveSimpleFilterFromSimpleFilter() throws Exception { } @Test - public void testRemoveSimpleEqualFilterFromSimpleFilter() throws Exception { + void testRemoveSimpleEqualFilterFromSimpleFilter() { final Filter filterOriginal = new EqualFilter("test"); final Filter filterCopy = new EqualFilter("test"); @@ -148,7 +148,7 @@ public void testRemoveSimpleEqualFilterFromSimpleFilter() throws Exception { } @Test - public void testRemoveSimpleEqualFilterFromTwoSimpleFilters() throws Exception { + void testRemoveSimpleEqualFilterFromTwoSimpleFilters() { final Filter filterOriginal = new EqualFilter("test"); final Filter filterCopy = new EqualFilter("test"); @@ -161,7 +161,7 @@ public void testRemoveSimpleEqualFilterFromTwoSimpleFilters() throws Exception { } @Test - public void testRemoveSimpleEqualFilterFromMultipleSimpleFilters() throws Exception { + void testRemoveSimpleEqualFilterFromMultipleSimpleFilters() { final Filter filterOriginal = new EqualFilter("test"); final Filter filterCopy = new EqualFilter("test"); @@ -178,7 +178,7 @@ public void testRemoveSimpleEqualFilterFromMultipleSimpleFilters() throws Except } @Test - public void testRemoveNullFromSingleSimpleFilter() throws Exception { + void testRemoveNullFromSingleSimpleFilter() { final Filter filter = ThresholdFilter.createFilter(Level.ERROR, null, null); filterable.addFilter(filter); @@ -187,7 +187,7 @@ public void testRemoveNullFromSingleSimpleFilter() throws Exception { } @Test - public void testRemoveNonExistingFilterFromSingleSimpleFilter() throws Exception { + void testRemoveNonExistingFilterFromSingleSimpleFilter() { final Filter filter = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter newFilter = ThresholdFilter.createFilter(Level.WARN, null, null); @@ -197,7 +197,7 @@ public void testRemoveNonExistingFilterFromSingleSimpleFilter() throws Exception } @Test - public void testRemoveSimpleFilterFromCompositeFilter() { + void testRemoveSimpleFilterFromCompositeFilter() { final Filter filter1 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter filter2 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter compositeFilter = CompositeFilter.createFilters(new Filter[] {filter1, filter2}); @@ -212,7 +212,7 @@ public void testRemoveSimpleFilterFromCompositeFilter() { } @Test - public void testRemoveSimpleFilterFromCompositeAndSimpleFilter() { + void testRemoveSimpleFilterFromCompositeAndSimpleFilter() { final Filter filter1 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter filter2 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter compositeFilter = CompositeFilter.createFilters(new Filter[] {filter1, filter2}); @@ -228,7 +228,7 @@ public void testRemoveSimpleFilterFromCompositeAndSimpleFilter() { } @Test - public void testRemoveCompositeFilterFromCompositeFilter() { + void testRemoveCompositeFilterFromCompositeFilter() { final Filter filter1 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter filter2 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter compositeFilter = CompositeFilter.createFilters(new Filter[] {filter1, filter2}); @@ -239,7 +239,7 @@ public void testRemoveCompositeFilterFromCompositeFilter() { } @Test - public void testRemoveFiltersFromComposite() { + void testRemoveFiltersFromComposite() { final Filter filter1 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter filter2 = ThresholdFilter.createFilter(Level.ERROR, null, null); final Filter compositeFilter = CompositeFilter.createFilters(new Filter[] {filter1, filter2}); From e6a5ee39aa689d9742201f1ace0a364bd009fadb Mon Sep 17 00:00:00 2001 From: Jeff Thomas Date: Sun, 2 Mar 2025 23:41:43 +0100 Subject: [PATCH 12/12] Renamed and updated changelog. (#3086) --- ...luginFactory.xml => 3086_change_RegexFilter_cleanup_API.xml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/changelog/.3.x.x/{3086_change_RegexFilter_remove_patternflags_from_PluginFactory.xml => 3086_change_RegexFilter_cleanup_API.xml} (80%) diff --git a/src/changelog/.3.x.x/3086_change_RegexFilter_remove_patternflags_from_PluginFactory.xml b/src/changelog/.3.x.x/3086_change_RegexFilter_cleanup_API.xml similarity index 80% rename from src/changelog/.3.x.x/3086_change_RegexFilter_remove_patternflags_from_PluginFactory.xml rename to src/changelog/.3.x.x/3086_change_RegexFilter_cleanup_API.xml index 0e61653f85c..e503826efe3 100644 --- a/src/changelog/.3.x.x/3086_change_RegexFilter_remove_patternflags_from_PluginFactory.xml +++ b/src/changelog/.3.x.x/3086_change_RegexFilter_cleanup_API.xml @@ -5,6 +5,6 @@ type="fixed"> - Removed 'patternFlags' @PluginAttribute from RegexFilter @PluginFactory createFilter. + Reworked API for RegexFilter: added getXXX for configuration attributes, removed deprecated API.