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..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); @@ -53,12 +53,12 @@ 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); } @Test - public void testAddMultipleEqualSimpleFilter() throws Exception { + void testAddMultipleEqualSimpleFilter() { final Filter filter = new EqualFilter("test"); filterable.addFilter(filter); @@ -66,12 +66,12 @@ 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); } @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); @@ -92,12 +92,12 @@ 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); } @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); @@ -108,12 +108,12 @@ 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); } @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); @@ -124,12 +124,12 @@ 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); } @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"); @@ -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()); @@ -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}); @@ -223,12 +223,12 @@ 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); } @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}); @@ -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 a3e8bf3d025..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 @@ -18,6 +18,10 @@ 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.assertTrue; @@ -33,15 +37,26 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -public class RegexFilterTest { +class RegexFilterTest { @BeforeAll - public static void before() { - StatusLogger.getLogger().setLevel(Level.OFF); + static void before() { + StatusLogger.getLogger().getFallbackListener().setLevel(Level.OFF); } @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,26 +74,22 @@ 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); } @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)); - } + void testNoMsg() { + + final RegexFilter filter = RegexFilter.newBuilder() + .setRegex(".* test .*") + .setUseRawMsg(false) + .build(); + + assertNotNull(filter); - @Test - public void testNoMsg() throws Exception { - final RegexFilter filter = RegexFilter.createFilter(".* test .*", null, false, null, null); 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)); @@ -86,28 +97,105 @@ 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); + + 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(); + + 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"); + + assertNull(builder.build()); + } } 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 400bd42e01e..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 @@ -16,10 +16,7 @@ */ 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.Objects; import java.util.regex.Pattern; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; @@ -28,140 +25,312 @@ import org.apache.logging.log4j.core.Logger; 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.PluginAttribute; -import org.apache.logging.log4j.plugins.PluginElement; +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; /** - * 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. + *
+ * 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}. + *
*/ @Configurable(elementType = Filter.ELEMENT_TYPE, printObject = true) +@NullMarked @Plugin public final class RegexFilter extends AbstractFilter { - private static final int DEFAULT_PATTERN_FLAGS = 0; + /** 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 is not configured or cannot be compiled to a pattern + */ + 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."); + } + + this.useRawMessage = Boolean.TRUE.equals(builder.useRawMsg); + + try { + this.pattern = Pattern.compile(builder.regex); + } catch (final Exception ex) { + throw new IllegalArgumentException("Unable to compile regular expression: '" + builder.regex + "'.", ex); + } + } + + /** + * Returns the compiled regular-expression pattern. + * @return the pattern (will never be {@code null} + */ + 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 true} if the raw message should be used; otherwise, {@code false} + */ + public boolean isUseRawMessage() { + return this.useRawMessage; + } + + /** + * {@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: + *
+ * This implementation performs the filter evaluation against the given message. + *
+ *+ * The following method arguments are ignored by this filter method implementation: + *
+ * This implementation performs the filter evaluation against the given message. + *
+ *+ * The following method arguments are ignored by this filter method implementation: + *
+ * If the given '{@code msg}' is {@code null} the configured {@code onMismatch} result will be returned. + *
+ * @param msg the message + * @return the {@code onMatch} result if the pattern matches; otherwise, the {@code onMismatch} result + */ + public Result filter(final @Nullable String msg) { + return (msg != null && 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. + *
+ *+ * 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. + *
+ *+ * 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 StructuredDataMessage) + ? message.getFormat() + : message.getFormattedMessage(); } + /** {@inheritDoc} */ @Override public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("useRaw=").append(useRawMessage); - sb.append(", pattern=").append(pattern.toString()); - return sb.toString(); + return "useRawMessage=" + useRawMessage + ", pattern=" + pattern; } /** - * Creates a Filter that matches a regular expression. - * - * @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. - * @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 - * @throws IllegalArgumentException + * Creates a new builder instance. + * @return the new builder instance */ - // 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) - // @formatter:on - throws IllegalArgumentException, IllegalAccessException { - 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); + public static Builder newBuilder() { + return new Builder(); } - private static int toPatternFlags(final String[] patternFlags) - throws IllegalArgumentException, IllegalAccessException { - if (patternFlags == null || patternFlags.length == 0) { - return DEFAULT_PATTERN_FLAGS; + /** + * A {@link RegexFilter} builder instance. + */ + public static final class Builder extends AbstractFilterBuilder