You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by vy...@apache.org on 2023/06/05 20:04:39 UTC

[logging-log4j2] 01/01: Set the default `minLevel` and `maxLevel` of `LevelRangeFilter` to `OFF` and `ALL`, respectively

This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LevelRangeFilter-defaults
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 0a097b4ffb2234d16dddec3a59ca90f3238b476a
Author: Volkan Yazıcı <vo...@yazi.ci>
AuthorDate: Mon Jun 5 22:04:23 2023 +0200

    Set the default `minLevel` and `maxLevel` of `LevelRangeFilter` to `OFF` and `ALL`, respectively
---
 .../log4j/core/filter/LevelRangeFilterTest.java    | 84 +++++++++++++++-------
 .../log4j/core/filter/LevelRangeFilter.java        | 73 ++++++++++++-------
 .../1503_change_defaults_for_LevelRangeFilter.xml  | 25 +++++++
 src/site/xdoc/manual/filters.xml                   | 54 ++++++++++++++
 4 files changed, 186 insertions(+), 50 deletions(-)

diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/LevelRangeFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/LevelRangeFilterTest.java
index 622503147f..7eab683c69 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/LevelRangeFilterTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/LevelRangeFilterTest.java
@@ -17,41 +17,77 @@
 package org.apache.logging.log4j.core.filter;
 
 import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Filter.Result;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.message.SimpleMessage;
+import org.assertj.core.api.SoftAssertions;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
 
-import static org.junit.jupiter.api.Assertions.*;
+import static org.apache.logging.log4j.core.filter.LevelRangeFilter.createFilter;
+import static org.assertj.core.api.Assertions.assertThat;
 
-public class LevelRangeFilterTest {
+class LevelRangeFilterTest {
 
     @Test
-    public void testLevels() {
-        final LevelRangeFilter filter = LevelRangeFilter.createFilter(Level.ERROR, Level.INFO, null, null);
-        filter.start();
-        assertTrue(filter.isStarted());
-        assertSame(Filter.Result.DENY, filter.filter(null, Level.DEBUG, null, (Object) null, (Throwable) null));
-        assertSame(Filter.Result.NEUTRAL, filter.filter(null, Level.ERROR, null, (Object) null, (Throwable) null));
-        LogEvent event = Log4jLogEvent.newBuilder() //
-                .setLevel(Level.DEBUG) //
-                .setMessage(new SimpleMessage("Test")) //
-                .build();
-        assertSame(Filter.Result.DENY, filter.filter(event));
-        event = Log4jLogEvent.newBuilder() //
-                .setLevel(Level.ERROR) //
-                .setMessage(new SimpleMessage("Test")) //
-                .build();
-        assertSame(Filter.Result.NEUTRAL, filter.filter(event));
+    void verify_constants() {
+        assertThat(LevelRangeFilter.DEFAULT_MIN_LEVEL).isEqualTo(Level.OFF);
+        assertThat(LevelRangeFilter.DEFAULT_MAX_LEVEL).isEqualTo(Level.ALL);
+        assertThat(LevelRangeFilter.DEFAULT_ON_MATCH).isEqualTo(Result.NEUTRAL);
+        assertThat(LevelRangeFilter.DEFAULT_ON_MISMATCH).isEqualTo(Result.DENY);
+    }
+
+    @Test
+    void verify_defaults() {
+        final LevelRangeFilter filter = createFilter(null, null, null, null);
+        assertThat(filter.getMinLevel()).isEqualTo(Level.OFF);
+        assertThat(filter.getMaxLevel()).isEqualTo(Level.ALL);
+        assertThat(filter.getOnMatch()).isEqualTo(Result.NEUTRAL);
+        assertThat(filter.getOnMismatch()).isEqualTo(Result.DENY);
+    }
+
+    @ParameterizedTest
+    @MethodSource("org.apache.logging.log4j.Level#values")
+    void default_should_match_all_levels(final Level level) {
+        final LevelRangeFilter filter = createFilter(null, null, null, null);
+        assertThat(filter.filter(createEvent(level))).isEqualTo(LevelRangeFilter.DEFAULT_ON_MATCH);
     }
 
     @Test
-    public void testMinimumOnlyLevel() {
-        final LevelRangeFilter filter = LevelRangeFilter.createFilter(Level.ERROR, null, null, null);
-        filter.start();
-        assertTrue(filter.isStarted());
-        assertSame(Filter.Result.NEUTRAL, filter.filter(null, Level.ERROR, null, (Object) null, (Throwable) null));
+    void overriding_defaults_should_be_effective() {
+
+        // Choose a configuration
+        final Level minLevel = Level.ERROR;
+        final Level maxLevel = Level.WARN;
+        final Result onMatch = Result.ACCEPT;
+        final Result onMismatch = Result.NEUTRAL;
+
+        // Verify we deviate from the defaults
+        assertThat(minLevel).isNotEqualTo(LevelRangeFilter.DEFAULT_MIN_LEVEL);
+        assertThat(maxLevel).isNotEqualTo(LevelRangeFilter.DEFAULT_MAX_LEVEL);
+        assertThat(onMatch).isNotEqualTo(LevelRangeFilter.DEFAULT_ON_MATCH);
+        assertThat(onMismatch).isNotEqualTo(LevelRangeFilter.DEFAULT_ON_MISMATCH);
+
+        // Verify the filtering
+        final LevelRangeFilter filter = createFilter(minLevel, maxLevel, onMatch, onMismatch);
+        final SoftAssertions assertions = new SoftAssertions();
+        for (final Level level : Level.values()) {
+            final Result expectedResult = level.isInRange(minLevel, maxLevel) ? onMatch : onMismatch;
+            assertions.assertThat(filter.filter(createEvent(level))).isEqualTo(expectedResult);
+        }
+        assertions.assertAll();
+
+    }
+
+    private static LogEvent createEvent(final Level level) {
+        final SimpleMessage message = new SimpleMessage("test message at level " + level);
+        return Log4jLogEvent
+                .newBuilder()
+                .setLevel(level)
+                .setMessage(message)
+                .build();
     }
 
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/LevelRangeFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/LevelRangeFilter.java
index 3f5194ce87..6207717ee0 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/LevelRangeFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/LevelRangeFilter.java
@@ -29,13 +29,12 @@ import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.util.PerformanceSensitive;
 
 /**
- * This filter returns the {@code onMatch} result if the level in the {@code LogEvent} is in the range of the configured
- * min and max levels, otherwise it returns {@code onMismatch} value . For example, if the filter is configured with
- * {@link Level#ERROR} and {@link Level#INFO} and the LogEvent contains {@link Level#WARN} then the onMatch value will
- * be returned since {@link Level#WARN WARN} events are in between {@link Level#ERROR ERROR} and {@link Level#INFO
- * INFO}.
+ * This filter returns the {@link #onMatch} result if the level of the {@link LogEvent} is in the range of the configured {@link #minLevel} and {@link #maxLevel} values, otherwise it returns the {@link #onMismatch} result.
+ * The default values for {@link #minLevel} and {@link #maxLevel} are set to {@link Level#OFF} and {@link Level#ALL}, respectively.
+ * The default values for {@link #onMatch} and {@link #onMismatch} are set to {@link Result#NEUTRAL} and {@link Result#DENY}, respectively.
  * <p>
- * The default Levels are both {@link Level#ERROR ERROR}.
+ * The levels get compared by their associated integral values; {@link Level#OFF} has an integral value of 0, {@link Level#FATAL} 100, {@link Level#ERROR} 200, and so on.
+ * For example, if the filter is configured with {@link #maxLevel} set to {@link Level#INFO}, the filter will return {@link #onMismatch} result for {@link LogEvent}s of level with higher integral values; {@link Level#DEBUG}, {@link Level#TRACE}, etc.
  * </p>
  */
 @Plugin(name = "LevelRangeFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
@@ -43,33 +42,49 @@ import org.apache.logging.log4j.util.PerformanceSensitive;
 public final class LevelRangeFilter extends AbstractFilter {
 
     /**
-     * Creates a ThresholdFilter.
+     * The default minimum level threshold.
+     */
+    public static final Level DEFAULT_MIN_LEVEL = Level.OFF;
+
+    /**
+     * THe default maximum level threshold.
+     */
+    public static final Level DEFAULT_MAX_LEVEL = Level.ALL;
+
+    /**
+     * The default result on a match.
+     */
+    public static final Result DEFAULT_ON_MATCH = Result.NEUTRAL;
+
+    /**
+     * The default result on a mismatch.
+     */
+    public static final Result DEFAULT_ON_MISMATCH = Result.DENY;
+
+    /**
+     * Creates an instance with the provided properties.
      *
-     * @param minLevel
-     *            The minimum log Level.
-     * @param maxLevel
-     *            The maximum log Level.
-     * @param match
-     *            The action to take on a match.
-     * @param mismatch
-     *            The action to take on a mismatch.
-     * @return The created ThresholdFilter.
+     * @param minLevel the minimum level threshold
+     * @param maxLevel the maximum level threshold
+     * @param onMatch the result to return on a match
+     * @param onMismatch the result to return on a mismatch
+     * @return a new instance
      */
-    // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder
     @PluginFactory
     public static LevelRangeFilter createFilter(
             // @formatter:off
             @PluginAttribute("minLevel") final Level minLevel,
             @PluginAttribute("maxLevel") final Level maxLevel,
-            @PluginAttribute("onMatch") final Result match,
-            @PluginAttribute("onMismatch") final Result mismatch) {
+            @PluginAttribute("onMatch") final Result onMatch,
+            @PluginAttribute("onMismatch") final Result onMismatch) {
             // @formatter:on
-        final Level actualMinLevel = minLevel == null ? Level.ERROR : minLevel;
-        final Level actualMaxLevel = maxLevel == null ? Level.ERROR : maxLevel;
-        final Result onMatch = match == null ? Result.NEUTRAL : match;
-        final Result onMismatch = mismatch == null ? Result.DENY : mismatch;
-        return new LevelRangeFilter(actualMinLevel, actualMaxLevel, onMatch, onMismatch);
+        final Level effectiveMinLevel = minLevel == null ? DEFAULT_MIN_LEVEL : minLevel;
+        final Level effectiveMaxLevel = maxLevel == null ? DEFAULT_MAX_LEVEL : maxLevel;
+        final Result effectiveOnMatch = onMatch == null ? DEFAULT_ON_MATCH : onMatch;
+        final Result effectiveOnMismatch = onMismatch == null ? DEFAULT_ON_MISMATCH : onMismatch;
+        return new LevelRangeFilter(effectiveMinLevel, effectiveMaxLevel, effectiveOnMatch, effectiveOnMismatch);
     }
+
     private final Level maxLevel;
 
     private final Level minLevel;
@@ -81,7 +96,7 @@ public final class LevelRangeFilter extends AbstractFilter {
     }
 
     private Result filter(final Level level) {
-        return level.isInRange(this.minLevel, this.maxLevel) ? onMatch : onMismatch;
+        return level.isInRange(minLevel, maxLevel) ? onMatch : onMismatch;
     }
 
     @Override
@@ -176,17 +191,23 @@ public final class LevelRangeFilter extends AbstractFilter {
         return filter(level);
     }
 
+    /**
+     * @return the minimum level threshold
+     */
     public Level getMinLevel() {
         return minLevel;
     }
 
+    /**
+     * @return the maximum level threshold
+     */
     public Level getMaxLevel() {
         return maxLevel;
     }
 
     @Override
     public String toString() {
-        return minLevel.toString();
+        return String.format("[%s,%s]", minLevel, maxLevel);
     }
 
 }
diff --git a/src/changelog/.2.x.x/1503_change_defaults_for_LevelRangeFilter.xml b/src/changelog/.2.x.x/1503_change_defaults_for_LevelRangeFilter.xml
new file mode 100644
index 0000000000..f08212ca6c
--- /dev/null
+++ b/src/changelog/.2.x.x/1503_change_defaults_for_LevelRangeFilter.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to you under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns="http://logging.apache.org/log4j/changelog"
+       xsi:schemaLocation="http://logging.apache.org/log4j/changelog https://logging.apache.org/log4j/changelog-0.1.1.xsd"
+       type="changed">
+  <issue id="1503" link="https://github.com/apache/logging-log4j2/pulls/1503"/>
+  <author id="vy"/>
+  <description format="asciidoc">Set the default `minLevel` and `maxLevel` of `LevelRangeFilter` to `OFF` and `ALL`, respectively</description>
+</entry>
diff --git a/src/site/xdoc/manual/filters.xml b/src/site/xdoc/manual/filters.xml
index c066e414c1..2947b993bc 100644
--- a/src/site/xdoc/manual/filters.xml
+++ b/src/site/xdoc/manual/filters.xml
@@ -235,6 +235,60 @@
   </Loggers>
 </Configuration>]]></pre>
         </subsection>
+
+        <a name="LevelRangeFilter"/>
+        <subsection name="LevelRangeFilter">
+          <p>
+            <code>LevelRangeFilter</code> allows filtering against a level range, where levels get compared by their associated integral values; <code>OFF</code> has an integral value of 0, <code>FATAL</code> 100, <code>ERROR</code> 200, and so on.
+          </p>
+          <table>
+            <caption align="top">Map Filter Parameters</caption>
+            <tr>
+              <th>Parameter Name</th>
+              <th>Type</th>
+              <th>Description</th>
+            </tr>
+            <tr>
+              <td><code>minLevel</code></td>
+              <td><code>Level</code></td>
+              <td>the minimum level threshold (defaults to <code>OFF</code>, which has an integral value of 0)</td>
+            </tr>
+            <tr>
+              <td><code>maxLevel</code></td>
+              <td><code>Level</code></td>
+              <td>the maximum level threshold (defaults to <code>ALL</code>, which has an integral value of <code>Integer.MAX_VALUE</code>)</td>
+            </tr>
+            <tr>
+              <td><code>onMatch</code></td>
+              <td><code>Filter.Result</code></td>
+              <td>the result to return on a match, where allowed values are <code>ACCEPT</code>, <code>DENY</code> or <code>NEUTRAL</code> (default)</td>
+            </tr>
+            <tr>
+              <td><code>onMismatch</code></td>
+              <td><code>Filter.Result</code></td>
+              <td>the result to return on a mismatch, where allowed values are <code>ACCEPT</code>, <code>DENY</code> (default) or <code>NEUTRAL</code></td>
+            </tr>
+          </table>
+          <p>
+            In the following example configuration, a <code>LevelRangeFilter</code> is configured with <code>maxLevel</code> set to <code>INFO</code>.
+            The filter will return <code>onMismatch</code> result (i.e., <code>DENY</code>, the default) for log events of level with higher integral values than <code>INFO</code>; i.e., <code>DEBUG</code>, <code>TRACE</code>, etc.
+          </p>
+          <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="WARN" name="MyApp">
+  <Appenders>
+    <Console name="STDOUT">
+      <LevelRangeFilter maxLevel="INFO"/>
+      <PatternLayout pattern="%d %p %c{1.} [%t] %m%n"/>
+    </Console>
+  </Appenders>
+  <Loggers>
+    <Root level="ERROR">
+      <AppenderRef ref="STDOUT"/>
+    </Root>
+  </Loggers>
+</Configuration>]]></pre>
+        </subsection>
+
         <a name="MapFilter"/>
         <subsection name="MapFilter">
           <p>