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