vy commented on code in PR #3512:
URL: https://github.com/apache/logging-log4j2/pull/3512#discussion_r1995087013


##########
log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java:
##########
@@ -100,59 +242,191 @@ private String targetMessageTest(final Message message) {
                 : message.getFormattedMessage();
     }
 
-    private Result filter(final String msg) {
-        if (msg == null) {
-            return onMismatch;
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "useRawMessage=" + useRawMessage + ", pattern=" + 
pattern.toString();
+    }
+
+    /**
+     * Creates a new builder instance.
+     * @return the new builder instance
+     */
+    @PluginBuilderFactory
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /**
+     * A {@link RegexFilter} builder instance.
+     */
+    public static final class Builder extends 
AbstractFilterBuilder<RegexFilter.Builder>
+            implements org.apache.logging.log4j.core.util.Builder<RegexFilter> 
{
+
+        /* NOTE: LOG4J-3086 - No patternFlags in builder - this functionality 
has been deprecated/removed. */
+
+        /**
+         * The regular expression to match.
+         */
+        @PluginBuilderAttribute
+        @Required(message = "No 'regex' provided for RegexFilter")
+        private @Nullable 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 @Nullable 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 = Assert.requireNonEmpty(regex, "The 'regex' attribute 
must not be null or empty.");
+            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 (Strings.isNotEmpty(this.regex));

Review Comment:
   ```suggestion
               return Strings.isNotEmpty(this.regex);
   ```



##########
log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java:
##########
@@ -29,68 +29,210 @@
 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.PluginFactory;
+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.MessageFormatMessage;
 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.util.Strings;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
 
 /**
- * A filter that matches the given regular expression pattern against messages.
+ * 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.
  */
 @Plugin(name = "RegexFilter", category = Node.CATEGORY, elementType = 
Filter.ELEMENT_TYPE, printObject = true)
+@NullMarked
 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);
+
+        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}
+     * <p>
+     *   This implementation performs the filter evaluation against the given 
message formatted with
+     *   the given parameters.
+     * </p>
+     * <p>
+     *   The following method arguments are ignored by this filter method 
implementation:
+     *   <ul>
+     *     <li>{@code logger}</li>
+     *     <li>{@code level}</li>
+     *     <li>{@code marker}</li>
+     *   </ul>
+     * </p>
+     */
     @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));
+            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}
+     * <p>
+     *   This implementation performs the filter evaluation against the given 
message.
+     * </p>
+     * <p>
+     *   The following method arguments are ignored by this filter method 
implementation:
+     *   <ul>
+     *     <li>{@code logger}</li>
+     *     <li>{@code level}</li>
+     *     <li>{@code marker}</li>
+     *     <li>{@code throwable}</li>
+     *   </ul>
+     * </p>
+     */
     @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());
+            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}
+     * <p>
+     *   This implementation performs the filter evaluation against the given 
message.
+     * </p>
+     * <p>
+     *   The following method arguments are ignored by this filter method 
implementation:
+     *   <ul>
+     *     <li>{@code logger}</li>
+     *     <li>{@code level}</li>
+     *     <li>{@code marker}</li>
+     *     <li>{@code throwable}</li>
+     *   </ul>
+     * </p>
+     */
     @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 = targetMessageTest(msg);
-        return filter(text);
+            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}
+     *
+     * @throws NullPointerException if the {@code event} argument is {@code 
null}
+     */
     @Override
     public Result filter(final LogEvent event) {
-        final String text = targetMessageTest(event.getMessage());
-        return filter(text);
+        Objects.requireNonNull(event, "The 'event' argument must not be 
null.");

Review Comment:
   ```suggestion
           Objects.requireNonNull(event, "event");
   ```



##########
log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java:
##########
@@ -100,59 +242,191 @@ private String targetMessageTest(final Message message) {
                 : message.getFormattedMessage();
     }
 
-    private Result filter(final String msg) {
-        if (msg == null) {
-            return onMismatch;
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "useRawMessage=" + useRawMessage + ", pattern=" + 
pattern.toString();
+    }
+
+    /**
+     * Creates a new builder instance.
+     * @return the new builder instance
+     */
+    @PluginBuilderFactory
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /**
+     * A {@link RegexFilter} builder instance.
+     */
+    public static final class Builder extends 
AbstractFilterBuilder<RegexFilter.Builder>
+            implements org.apache.logging.log4j.core.util.Builder<RegexFilter> 
{
+
+        /* NOTE: LOG4J-3086 - No patternFlags in builder - this functionality 
has been deprecated/removed. */
+
+        /**
+         * The regular expression to match.
+         */
+        @PluginBuilderAttribute
+        @Required(message = "No 'regex' provided for RegexFilter")

Review Comment:
   Please don't provide a failure message for cases where _the failure system_ 
should be providing the necessary context.
   
   ```suggestion
           @Required
   ```



##########
log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java:
##########
@@ -100,59 +242,191 @@ private String targetMessageTest(final Message message) {
                 : message.getFormattedMessage();
     }
 
-    private Result filter(final String msg) {
-        if (msg == null) {
-            return onMismatch;
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "useRawMessage=" + useRawMessage + ", pattern=" + 
pattern.toString();
+    }
+
+    /**
+     * Creates a new builder instance.
+     * @return the new builder instance
+     */
+    @PluginBuilderFactory
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /**
+     * A {@link RegexFilter} builder instance.
+     */
+    public static final class Builder extends 
AbstractFilterBuilder<RegexFilter.Builder>
+            implements org.apache.logging.log4j.core.util.Builder<RegexFilter> 
{
+
+        /* NOTE: LOG4J-3086 - No patternFlags in builder - this functionality 
has been deprecated/removed. */
+
+        /**
+         * The regular expression to match.
+         */
+        @PluginBuilderAttribute
+        @Required(message = "No 'regex' provided for RegexFilter")
+        private @Nullable 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 @Nullable 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 = Assert.requireNonEmpty(regex, "The 'regex' attribute 
must not be null or empty.");
+            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 (Strings.isNotEmpty(this.regex));
+        }
+
+        /**
+         * 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 @Nullable RegexFilter build() {
+
+            // validate the "regex" attribute
+            if (Strings.isEmpty(this.regex)) {
+                LOGGER.error("Unable to create RegexFilter: The 'regex' 
attribute be set to a non-empty String.");
+                return null;
+            }
+
+            // build with *safety* to not throw exceptions
+            try {
+                return new RegexFilter(this);
+            } catch (final Exception ex) {
+                LOGGER.error("Unable to create RegexFilter. {}", 
ex.getMessage(), ex);
+                return null;
+            }
         }
-        final Matcher m = pattern.matcher(msg);
-        return m.matches() ? onMatch : onMismatch;
     }
 
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder();
-        sb.append("useRaw=").append(useRawMessage);
-        sb.append(", pattern=").append(pattern.toString());
-        return sb.toString();
+    /*
+     * 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
+    private static final int DEFAULT_PATTERN_FLAGS = 0;

Review Comment:
   AFAIU, this constant is only used in `toPatternFlags()`, could you move it 
into that method, please?



##########
log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java:
##########
@@ -100,59 +242,191 @@ private String targetMessageTest(final Message message) {
                 : message.getFormattedMessage();
     }
 
-    private Result filter(final String msg) {
-        if (msg == null) {
-            return onMismatch;
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "useRawMessage=" + useRawMessage + ", pattern=" + 
pattern.toString();
+    }
+
+    /**
+     * Creates a new builder instance.
+     * @return the new builder instance
+     */
+    @PluginBuilderFactory
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /**
+     * A {@link RegexFilter} builder instance.
+     */
+    public static final class Builder extends 
AbstractFilterBuilder<RegexFilter.Builder>
+            implements org.apache.logging.log4j.core.util.Builder<RegexFilter> 
{
+
+        /* NOTE: LOG4J-3086 - No patternFlags in builder - this functionality 
has been deprecated/removed. */
+
+        /**
+         * The regular expression to match.
+         */
+        @PluginBuilderAttribute
+        @Required(message = "No 'regex' provided for RegexFilter")
+        private @Nullable 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 @Nullable 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 = Assert.requireNonEmpty(regex, "The 'regex' attribute 
must not be null or empty.");
+            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 (Strings.isNotEmpty(this.regex));
+        }
+
+        /**
+         * 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 @Nullable RegexFilter build() {
+
+            // validate the "regex" attribute
+            if (Strings.isEmpty(this.regex)) {
+                LOGGER.error("Unable to create RegexFilter: The 'regex' 
attribute be set to a non-empty String.");
+                return null;
+            }
+
+            // build with *safety* to not throw exceptions
+            try {
+                return new RegexFilter(this);
+            } catch (final Exception ex) {
+                LOGGER.error("Unable to create RegexFilter. {}", 
ex.getMessage(), ex);
+                return null;
+            }
         }

Review Comment:
   We had [a `dev@` discussion about 
this](https://lists.apache.org/thread/h2oydyk6xld47ljttqvflbt4530o73vw), and 
the conclusion is to throw exception on failures while building components. 
Would you mind updating this `build()` logic accordingly, please?



##########
log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java:
##########
@@ -100,59 +242,191 @@ private String targetMessageTest(final Message message) {
                 : message.getFormattedMessage();
     }
 
-    private Result filter(final String msg) {
-        if (msg == null) {
-            return onMismatch;
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "useRawMessage=" + useRawMessage + ", pattern=" + 
pattern.toString();
+    }
+
+    /**
+     * Creates a new builder instance.
+     * @return the new builder instance
+     */
+    @PluginBuilderFactory
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /**
+     * A {@link RegexFilter} builder instance.
+     */
+    public static final class Builder extends 
AbstractFilterBuilder<RegexFilter.Builder>
+            implements org.apache.logging.log4j.core.util.Builder<RegexFilter> 
{
+
+        /* NOTE: LOG4J-3086 - No patternFlags in builder - this functionality 
has been deprecated/removed. */
+
+        /**
+         * The regular expression to match.
+         */
+        @PluginBuilderAttribute
+        @Required(message = "No 'regex' provided for RegexFilter")
+        private @Nullable 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 @Nullable 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 = Assert.requireNonEmpty(regex, "The 'regex' attribute 
must not be null or empty.");
+            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 (Strings.isNotEmpty(this.regex));
+        }
+
+        /**
+         * 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 @Nullable RegexFilter build() {
+
+            // validate the "regex" attribute
+            if (Strings.isEmpty(this.regex)) {
+                LOGGER.error("Unable to create RegexFilter: The 'regex' 
attribute be set to a non-empty String.");
+                return null;
+            }
+
+            // build with *safety* to not throw exceptions
+            try {
+                return new RegexFilter(this);
+            } catch (final Exception ex) {
+                LOGGER.error("Unable to create RegexFilter. {}", 
ex.getMessage(), ex);
+                return null;
+            }
         }
-        final Matcher m = pattern.matcher(msg);
-        return m.matches() ? onMatch : onMismatch;
     }
 
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder();
-        sb.append("useRaw=").append(useRawMessage);
-        sb.append(", pattern=").append(pattern.toString());
-        return sb.toString();
+    /*
+     * 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
+    private static final int DEFAULT_PATTERN_FLAGS = 0;
+
+    /**
+     * @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 String regex,
+            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();
+        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;
+    }
+
+    /**
+     * 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();
     }

Review Comment:
   We're adding a new deprecated method? Why don't we simply not add it?



##########
log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java:
##########
@@ -100,59 +242,191 @@ private String targetMessageTest(final Message message) {
                 : message.getFormattedMessage();
     }
 
-    private Result filter(final String msg) {
-        if (msg == null) {
-            return onMismatch;
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "useRawMessage=" + useRawMessage + ", pattern=" + 
pattern.toString();
+    }
+
+    /**
+     * Creates a new builder instance.
+     * @return the new builder instance
+     */
+    @PluginBuilderFactory
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /**
+     * A {@link RegexFilter} builder instance.
+     */
+    public static final class Builder extends 
AbstractFilterBuilder<RegexFilter.Builder>
+            implements org.apache.logging.log4j.core.util.Builder<RegexFilter> 
{
+
+        /* NOTE: LOG4J-3086 - No patternFlags in builder - this functionality 
has been deprecated/removed. */
+
+        /**
+         * The regular expression to match.
+         */
+        @PluginBuilderAttribute
+        @Required(message = "No 'regex' provided for RegexFilter")
+        private @Nullable 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 @Nullable 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 = Assert.requireNonEmpty(regex, "The 'regex' attribute 
must not be null or empty.");
+            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 (Strings.isNotEmpty(this.regex));
+        }
+
+        /**
+         * 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 @Nullable RegexFilter build() {
+
+            // validate the "regex" attribute
+            if (Strings.isEmpty(this.regex)) {
+                LOGGER.error("Unable to create RegexFilter: The 'regex' 
attribute be set to a non-empty String.");
+                return null;
+            }
+
+            // build with *safety* to not throw exceptions
+            try {
+                return new RegexFilter(this);
+            } catch (final Exception ex) {
+                LOGGER.error("Unable to create RegexFilter. {}", 
ex.getMessage(), ex);
+                return null;
+            }
         }
-        final Matcher m = pattern.matcher(msg);
-        return m.matches() ? onMatch : onMismatch;
     }
 
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder();
-        sb.append("useRaw=").append(useRawMessage);
-        sb.append(", pattern=").append(pattern.toString());
-        return sb.toString();
+    /*
+     * 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
+    private static final int DEFAULT_PATTERN_FLAGS = 0;
+
+    /**
+     * @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 String regex,
+            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();
+        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;
+    }
+
+    /**
+     * 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 patternFlags
-     *        An array of Strings where each String is a {@link 
Pattern#compile(String, int)} compilation flag.
-     * @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)
+            @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 {
-        if (regex == null) {
-            LOGGER.error("A regular expression must be provided for 
RegexFilter");
-            return null;
-        }
-        return new RegexFilter(
-                Boolean.TRUE.equals(useRawMsg), Pattern.compile(regex, 
toPatternFlags(patternFlags)), match, mismatch);
+
+        // LOG4J-3086 - pattern-flags can be embedded in RegEx expression
+        Objects.requireNonNull(regex, "The 'regex' argument must not be 
null.");

Review Comment:
   ```suggestion
           Objects.requireNonNull(regex, "regex");
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@logging.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


Reply via email to