You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2019/08/13 21:06:55 UTC

[logging-log4j2] branch release-2.x updated: [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().

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

ggregory pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


The following commit(s) were added to refs/heads/release-2.x by this push:
     new 4679a08  [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
4679a08 is described below

commit 4679a08d4899350f7ee19d050d2a96783b748066
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Tue Aug 13 17:06:48 2019 -0400

    [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
    
    Also allow a null output stream for convenience instead of an NPE.
---
 .../log4j/core/appender/OutputStreamAppender.java  | 351 +++++++++++----------
 .../core/appender/OutputStreamAppenderTest.java    | 230 +++++++-------
 src/changes/changes.xml                            |   3 +
 3 files changed, 302 insertions(+), 282 deletions(-)

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
index 7dfd187..dc6f352 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
@@ -1,174 +1,177 @@
-/*
- * 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.
- */
-package org.apache.logging.log4j.core.appender;
-
-import java.io.OutputStream;
-import java.io.Serializable;
-
-import org.apache.logging.log4j.core.Appender;
-import org.apache.logging.log4j.core.Core;
-import org.apache.logging.log4j.core.Filter;
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.config.Property;
-import org.apache.logging.log4j.core.config.plugins.Plugin;
-import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.core.config.plugins.PluginFactory;
-import org.apache.logging.log4j.core.layout.PatternLayout;
-import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
-
-/**
- * Appends log events to a given output stream using a layout.
- * <p>
- * Character encoding is handled within the Layout.
- * </p>
- */
-@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
-public final class OutputStreamAppender extends AbstractOutputStreamAppender<OutputStreamManager> {
-
-    /**
-     * Builds OutputStreamAppender instances.
-     */
-    public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
-            implements org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
-
-        private Filter filter;
-
-        private boolean follow = false;
-
-        private final boolean ignoreExceptions = true;
-
-        private OutputStream target;
-
-        @Override
-        public OutputStreamAppender build() {
-            final Layout<? extends Serializable> layout = getLayout();
-            final Layout<? extends Serializable> actualLayout = layout == null ? PatternLayout.createDefaultLayout()
-                    : layout;
-            return new OutputStreamAppender(getName(), actualLayout, filter, getManager(target, follow, actualLayout),
-                    ignoreExceptions, getPropertyArray());
-        }
-
-        public B setFollow(final boolean shouldFollow) {
-            this.follow = shouldFollow;
-            return asBuilder();
-        }
-
-        public B setTarget(final OutputStream aTarget) {
-            this.target = aTarget;
-            return asBuilder();
-        }
-    }
-
-    /**
-     * Holds data to pass to factory method.
-     */
-    private static class FactoryData {
-        private final Layout<? extends Serializable> layout;
-        private final String name;
-        private final OutputStream os;
-
-        /**
-         * Builds instances.
-         *
-         * @param os
-         *            The OutputStream.
-         * @param type
-         *            The name of the target.
-         * @param layout
-         *            A Serializable layout
-         */
-        public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
-            this.os = os;
-            this.name = type;
-            this.layout = layout;
-        }
-    }
-
-    /**
-     * Creates the manager.
-     */
-    private static class OutputStreamManagerFactory implements ManagerFactory<OutputStreamManager, FactoryData> {
-
-        /**
-         * Creates an OutputStreamManager.
-         *
-         * @param name
-         *            The name of the entity to manage.
-         * @param data
-         *            The data required to create the entity.
-         * @return The OutputStreamManager
-         */
-        @Override
-        public OutputStreamManager createManager(final String name, final FactoryData data) {
-            return new OutputStreamManager(data.os, data.name, data.layout, true);
-        }
-    }
-
-    private static OutputStreamManagerFactory factory = new OutputStreamManagerFactory();
-
-    /**
-     * Creates an OutputStream Appender.
-     *
-     * @param layout
-     *            The layout to use or null to get the default layout.
-     * @param filter
-     *            The Filter or null.
-     * @param target
-     *            an output stream.
-     * @param follow
-     *            If true will follow changes to the underlying output stream.
-     *            Use false as the default.
-     * @param name
-     *            The name of the Appender (required).
-     * @param ignore
-     *            If {@code "true"} (default) exceptions encountered when
-     *            appending events are logged; otherwise they are propagated to
-     *            the caller. Use true as the default.
-     * @return The ConsoleAppender.
-     */
-    @PluginFactory
-    public static OutputStreamAppender createAppender(Layout<? extends Serializable> layout, final Filter filter,
-            final OutputStream target, final String name, final boolean follow, final boolean ignore) {
-        if (name == null) {
-            LOGGER.error("No name provided for OutputStreamAppender");
-            return null;
-        }
-        if (layout == null) {
-            layout = PatternLayout.createDefaultLayout();
-        }
-        return new OutputStreamAppender(name, layout, filter, getManager(target, follow, layout), ignore, null);
-    }
-
-    private static OutputStreamManager getManager(final OutputStream target, final boolean follow,
-            final Layout<? extends Serializable> layout) {
-        final OutputStream os = new CloseShieldOutputStream(target);
-        final String managerName = target.getClass().getName() + "@" + Integer.toHexString(target.hashCode()) + '.'
-                + follow;
-        return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory);
-    }
-
-    @PluginBuilderFactory
-    public static Builder newBuilder() {
-        return new Builder();
-    }
-
-    private OutputStreamAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
-            final OutputStreamManager manager, final boolean ignoreExceptions, final Property[] properties) {
-        super(name, layout, filter, ignoreExceptions, true, properties, manager);
-    }
-
-}
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.core.appender;
+
+import java.io.OutputStream;
+import java.io.Serializable;
+
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Core;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.config.Property;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
+import org.apache.logging.log4j.core.util.NullOutputStream;
+
+/**
+ * Appends log events to a given output stream using a layout.
+ * <p>
+ * Character encoding is handled within the Layout.
+ * </p>
+ */
+@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
+public final class OutputStreamAppender extends AbstractOutputStreamAppender<OutputStreamManager> {
+
+    /**
+     * Builds OutputStreamAppender instances.
+     *
+     * @param <B>
+     *            The type to build.
+     */
+    public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
+            implements org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
+
+        private boolean follow = false;
+
+        private final boolean ignoreExceptions = true;
+
+        private OutputStream target;
+
+        @Override
+        public OutputStreamAppender build() {
+            final Layout<? extends Serializable> layout = getLayout();
+            final Layout<? extends Serializable> actualLayout = layout == null ? PatternLayout.createDefaultLayout()
+                    : layout;
+            return new OutputStreamAppender(getName(), actualLayout, getFilter(), getManager(target, follow, actualLayout),
+                    ignoreExceptions, getPropertyArray());
+        }
+
+        public B setFollow(final boolean shouldFollow) {
+            this.follow = shouldFollow;
+            return asBuilder();
+        }
+
+        public B setTarget(final OutputStream aTarget) {
+            this.target = aTarget;
+            return asBuilder();
+        }
+    }
+
+    /**
+     * Holds data to pass to factory method.
+     */
+    private static class FactoryData {
+        private final Layout<? extends Serializable> layout;
+        private final String name;
+        private final OutputStream os;
+
+        /**
+         * Builds instances.
+         *
+         * @param os
+         *            The OutputStream.
+         * @param type
+         *            The name of the target.
+         * @param layout
+         *            A Serializable layout
+         */
+        public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
+            this.os = os;
+            this.name = type;
+            this.layout = layout;
+        }
+    }
+
+    /**
+     * Creates the manager.
+     */
+    private static class OutputStreamManagerFactory implements ManagerFactory<OutputStreamManager, FactoryData> {
+
+        /**
+         * Creates an OutputStreamManager.
+         *
+         * @param name
+         *            The name of the entity to manage.
+         * @param data
+         *            The data required to create the entity.
+         * @return The OutputStreamManager
+         */
+        @Override
+        public OutputStreamManager createManager(final String name, final FactoryData data) {
+            return new OutputStreamManager(data.os, data.name, data.layout, true);
+        }
+    }
+
+    private static OutputStreamManagerFactory factory = new OutputStreamManagerFactory();
+
+    /**
+     * Creates an OutputStream Appender.
+     *
+     * @param layout
+     *            The layout to use or null to get the default layout.
+     * @param filter
+     *            The Filter or null.
+     * @param target
+     *            an output stream.
+     * @param follow
+     *            If true will follow changes to the underlying output stream.
+     *            Use false as the default.
+     * @param name
+     *            The name of the Appender (required).
+     * @param ignore
+     *            If {@code "true"} (default) exceptions encountered when
+     *            appending events are logged; otherwise they are propagated to
+     *            the caller. Use true as the default.
+     * @return The ConsoleAppender.
+     */
+    @PluginFactory
+    public static OutputStreamAppender createAppender(Layout<? extends Serializable> layout, final Filter filter,
+            final OutputStream target, final String name, final boolean follow, final boolean ignore) {
+        if (name == null) {
+            LOGGER.error("No name provided for OutputStreamAppender");
+            return null;
+        }
+        if (layout == null) {
+            layout = PatternLayout.createDefaultLayout();
+        }
+        return new OutputStreamAppender(name, layout, filter, getManager(target, follow, layout), ignore, null);
+    }
+
+    private static OutputStreamManager getManager(final OutputStream target, final boolean follow,
+            final Layout<? extends Serializable> layout) {
+        final OutputStream os = target == null ? NullOutputStream.getInstance() : new CloseShieldOutputStream(target);
+        final OutputStream targetRef = target == null ? os : target;
+        final String managerName = targetRef.getClass().getName() + "@" + Integer.toHexString(targetRef.hashCode())
+                + '.' + follow;
+        return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory);
+    }
+
+    @PluginBuilderFactory
+    public static <B extends Builder<B>> B newBuilder() {
+        return new Builder<B>().asBuilder();
+    }
+
+    private OutputStreamAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
+            final OutputStreamManager manager, final boolean ignoreExceptions, final Property[] properties) {
+        super(name, layout, filter, ignoreExceptions, true, properties, manager);
+    }
+
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
index 00af014..c1448bf 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
@@ -1,108 +1,122 @@
-/*
- * 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.
- */
-package org.apache.logging.log4j.core.appender;
-
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.OutputStream;
-import java.sql.SQLException;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.Appender;
-import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.layout.PatternLayout;
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-
-/**
- * Tests {@link OutputStreamAppender}.
- */
-public class OutputStreamAppenderTest {
-
-    private static final String TEST_MSG = "FOO ERROR";
-
-    @Rule
-    public TestName testName = new TestName();
-
-    private String getName(final OutputStream out) {
-        return out.getClass().getSimpleName() + "." + testName.getMethodName();
-    }
-
-    /**
-     * Tests that you can add an output stream appender dynamically.
-     */
-    private void addAppender(final OutputStream outputStream, final String outputStreamName) {
-        final LoggerContext context = LoggerContext.getContext(false);
-        final Configuration config = context.getConfiguration();
-        final PatternLayout layout = PatternLayout.createDefaultLayout(config);
-        final Appender appender = OutputStreamAppender.createAppender(layout, null, outputStream, outputStreamName, false, true);
-        appender.start();
-        config.addAppender(appender);
-        ConfigurationTestUtils.updateLoggers(appender, config);
-    }
-
-    @Test
-    public void testOutputStreamAppenderToBufferedOutputStream() throws SQLException {
-        final ByteArrayOutputStream out = new ByteArrayOutputStream();
-        final OutputStream os = new BufferedOutputStream(out);
-        final String name = getName(out);
-        final Logger logger = LogManager.getLogger(name);
-        addAppender(os, name);
-        logger.error(TEST_MSG);
-        final String actual = out.toString();
-        Assert.assertTrue(actual, actual.contains(TEST_MSG));
-    }
-
-    @Test
-    public void testOutputStreamAppenderToByteArrayOutputStream() throws SQLException {
-        final OutputStream out = new ByteArrayOutputStream();
-        final String name = getName(out);
-        final Logger logger = LogManager.getLogger(name);
-        addAppender(out, name);
-        logger.error(TEST_MSG);
-        final String actual = out.toString();
-        Assert.assertTrue(actual, actual.contains(TEST_MSG));
-    }
-
-    /**
-     * Validates that the code pattern we use to add an appender on the fly
-     * works with a basic appender that is not the new OutputStream appender or
-     * new Writer appender.
-     */
-    @Test
-    public void testUpdatePatternWithFileAppender() {
-        final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
-        final Configuration config = ctx.getConfiguration();
-        // @formatter:off
-        final Appender appender = FileAppender.newBuilder()
-        .withFileName("target/" + getClass().getName() + ".log")
-        .withAppend(false).setName("File").setIgnoreExceptions(false)
-            .withBufferedIo(false)
-            .withBufferSize(4000)
-            .setConfiguration(config)
-            .build();
-        // @formatter:on
-        appender.start();
-        config.addAppender(appender);
-        ConfigurationTestUtils.updateLoggers(appender, config);
-        LogManager.getLogger().error("FOO MSG");
-    }
-}
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.core.appender;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.sql.SQLException;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.filter.NoMarkerFilter;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+
+/**
+ * Tests {@link OutputStreamAppender}.
+ */
+public class OutputStreamAppenderTest {
+
+    private static final String TEST_MSG = "FOO ERROR";
+
+    @Rule
+    public TestName testName = new TestName();
+
+    private String getName(final OutputStream out) {
+        return out.getClass().getSimpleName() + "." + testName.getMethodName();
+    }
+
+    /**
+     * Tests that you can add an output stream appender dynamically.
+     */
+    private void addAppender(final OutputStream outputStream, final String outputStreamName) {
+        final LoggerContext context = LoggerContext.getContext(false);
+        final Configuration config = context.getConfiguration();
+        final PatternLayout layout = PatternLayout.createDefaultLayout(config);
+        final Appender appender = OutputStreamAppender.createAppender(layout, null, outputStream, outputStreamName, false, true);
+        appender.start();
+        config.addAppender(appender);
+        ConfigurationTestUtils.updateLoggers(appender, config);
+    }
+
+    @Test
+    public void testBuildFilter() {
+        final NoMarkerFilter filter = NoMarkerFilter.newBuilder().build();
+        // @formatter:off
+        final OutputStreamAppender.Builder builder = OutputStreamAppender.newBuilder()
+                .setName("test")
+                .setFilter(filter);
+        // @formatter:on
+        Assert.assertEquals(filter, builder.getFilter());
+        final OutputStreamAppender appender = builder.build();
+        Assert.assertEquals(filter, appender.getFilter());
+    }
+    
+    @Test
+    public void testOutputStreamAppenderToBufferedOutputStream() throws SQLException {
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        final OutputStream os = new BufferedOutputStream(out);
+        final String name = getName(out);
+        final Logger logger = LogManager.getLogger(name);
+        addAppender(os, name);
+        logger.error(TEST_MSG);
+        final String actual = out.toString();
+        Assert.assertTrue(actual, actual.contains(TEST_MSG));
+    }
+
+    @Test
+    public void testOutputStreamAppenderToByteArrayOutputStream() throws SQLException {
+        final OutputStream out = new ByteArrayOutputStream();
+        final String name = getName(out);
+        final Logger logger = LogManager.getLogger(name);
+        addAppender(out, name);
+        logger.error(TEST_MSG);
+        final String actual = out.toString();
+        Assert.assertTrue(actual, actual.contains(TEST_MSG));
+    }
+
+    /**
+     * Validates that the code pattern we use to add an appender on the fly
+     * works with a basic appender that is not the new OutputStream appender or
+     * new Writer appender.
+     */
+    @Test
+    public void testUpdatePatternWithFileAppender() {
+        final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
+        final Configuration config = ctx.getConfiguration();
+        // @formatter:off
+        final Appender appender = FileAppender.newBuilder()
+        .withFileName("target/" + getClass().getName() + ".log")
+        .withAppend(false).setName("File").setIgnoreExceptions(false)
+            .withBufferedIo(false)
+            .withBufferSize(4000)
+            .setConfiguration(config)
+            .build();
+        // @formatter:on
+        appender.start();
+        config.addAppender(appender);
+        ConfigurationTestUtils.updateLoggers(appender, config);
+        LogManager.getLogger().error("FOO MSG");
+    }
+}
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index c3483bd..a9ec160 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -33,6 +33,9 @@
       <action issue="LOG4J2-2639" dev="rgoers" type="add">
         Add builder pattern to Logger interface.
       </action>
+      <action issue="LOG4J2-2673" dev="ggregory" type="fix" due-to="Yuichi Sugimura, Gary Gregory">
+        OutputStreamAppender.Builder ignores setFilter().
+      </action>
     </release>
     <release version="2.12.1" date="2019-08-06" description="GA Release 2.12.1">
       <action issue="LOG4J2-1946" dev="rgoers" type="fix" due-to="Igor Perelyotov">


Re: [logging-log4j2] branch release-2.x updated: [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().

Posted by Gary Gregory <ga...@gmail.com>.
I will look into it.

Gary

On Thu, Aug 15, 2019, 17:03 Ralph Goers <ra...@dslextreme.com> wrote:

> I believe you have not read this thread. I am not talking about the bug
> you fixed. I am talking the compatibility breakage you created.
>
> 1. The backward compatibility breakage only occurred on the release-2.x
> branch because revapi is essentially disabled on master. Too much has
> changed to bother keeping track.
> 2. I haven’t seen any commit messages indicating you committed anything to
> fix this.
> 3. The build is still failing for me.  Try running mvn clean install
> -DskipTests in log4j-core. It will break for you too.
>
> Please look at the Jenkins build and fix the problems by either reverting
> the breakage or by adding the recommended changes to revapi.json to
> document why compatibility was broken.
>
> Ralph
>
>
> > On Aug 15, 2019, at 4:54 PM, Gary Gregory <ga...@gmail.com>
> wrote:
> >
> > I fixed it already in both branches.
> >
> > Gary
> >
> > On Thu, Aug 15, 2019, 10:42 Ralph Goers <ra...@dslextreme.com>
> wrote:
> >
> >> Gary,
> >>
> >> Are you going to look into this?
> >>
> >> Ralph
> >>
> >>> On Aug 14, 2019, at 9:17 AM, Ralph Goers <ra...@dslextreme.com>
> >> wrote:
> >>>
> >>> Any update on this? I’d like my builds to work again.
> >>>
> >>> Ralph
> >>>
> >>>> On Aug 13, 2019, at 4:29 PM, Ralph Goers <ra...@dslextreme.com>
> >> wrote:
> >>>>
> >>>> Gary,
> >>>>
> >>>> It seems this change broker compatibility. Please see the Jenkins
> >> failure. You either need to resolve the code so compatibility is
> maintained
> >> or update revapi.json with the recommended changes.
> >>>>
> >>>> Ralph
> >>>>
> >>>>> On Aug 13, 2019, at 2:06 PM, ggregory@apache.org wrote:
> >>>>>
> >>>>> This is an automated email from the ASF dual-hosted git repository.
> >>>>>
> >>>>> ggregory pushed a commit to branch release-2.x
> >>>>> in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
> >>>>>
> >>>>>
> >>>>> The following commit(s) were added to refs/heads/release-2.x by this
> >> push:
> >>>>>  new 4679a08  [LOG4J2-2673] OutputStreamAppender.Builder ignores
> >> setFilter().
> >>>>> 4679a08 is described below
> >>>>>
> >>>>> commit 4679a08d4899350f7ee19d050d2a96783b748066
> >>>>> Author: Gary Gregory <ga...@gmail.com>
> >>>>> AuthorDate: Tue Aug 13 17:06:48 2019 -0400
> >>>>>
> >>>>> [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
> >>>>>
> >>>>> Also allow a null output stream for convenience instead of an NPE.
> >>>>> ---
> >>>>> .../log4j/core/appender/OutputStreamAppender.java  | 351
> >> +++++++++++----------
> >>>>> .../core/appender/OutputStreamAppenderTest.java    | 230
> +++++++-------
> >>>>> src/changes/changes.xml                            |   3 +
> >>>>> 3 files changed, 302 insertions(+), 282 deletions(-)
> >>>>>
> >>>>> diff --git
> >>
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>>>> index 7dfd187..dc6f352 100644
> >>>>> ---
> >>
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>>>> +++
> >>
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>>>> @@ -1,174 +1,177 @@
> >>>>> -/*
> >>>>> - * 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.
> >>>>> - */
> >>>>> -package org.apache.logging.log4j.core.appender;
> >>>>> -
> >>>>> -import java.io.OutputStream;
> >>>>> -import java.io.Serializable;
> >>>>> -
> >>>>> -import org.apache.logging.log4j.core.Appender;
> >>>>> -import org.apache.logging.log4j.core.Core;
> >>>>> -import org.apache.logging.log4j.core.Filter;
> >>>>> -import org.apache.logging.log4j.core.Layout;
> >>>>> -import org.apache.logging.log4j.core.config.Property;
> >>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> >>>>> -import
> >> org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
> >>>>> -import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> >>>>> -import org.apache.logging.log4j.core.layout.PatternLayout;
> >>>>> -import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
> >>>>> -
> >>>>> -/**
> >>>>> - * Appends log events to a given output stream using a layout.
> >>>>> - * <p>
> >>>>> - * Character encoding is handled within the Layout.
> >>>>> - * </p>
> >>>>> - */
> >>>>> -@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME,
> >> elementType = Appender.ELEMENT_TYPE, printObject = true)
> >>>>> -public final class OutputStreamAppender extends
> >> AbstractOutputStreamAppender<OutputStreamManager> {
> >>>>> -
> >>>>> -    /**
> >>>>> -     * Builds OutputStreamAppender instances.
> >>>>> -     */
> >>>>> -    public static class Builder<B extends Builder<B>> extends
> >> AbstractOutputStreamAppender.Builder<B>
> >>>>> -            implements
> >> org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
> >>>>> -
> >>>>> -        private Filter filter;
> >>>>> -
> >>>>> -        private boolean follow = false;
> >>>>> -
> >>>>> -        private final boolean ignoreExceptions = true;
> >>>>> -
> >>>>> -        private OutputStream target;
> >>>>> -
> >>>>> -        @Override
> >>>>> -        public OutputStreamAppender build() {
> >>>>> -            final Layout<? extends Serializable> layout =
> getLayout();
> >>>>> -            final Layout<? extends Serializable> actualLayout =
> >> layout == null ? PatternLayout.createDefaultLayout()
> >>>>> -                    : layout;
> >>>>> -            return new OutputStreamAppender(getName(), actualLayout,
> >> filter, getManager(target, follow, actualLayout),
> >>>>> -                    ignoreExceptions, getPropertyArray());
> >>>>> -        }
> >>>>> -
> >>>>> -        public B setFollow(final boolean shouldFollow) {
> >>>>> -            this.follow = shouldFollow;
> >>>>> -            return asBuilder();
> >>>>> -        }
> >>>>> -
> >>>>> -        public B setTarget(final OutputStream aTarget) {
> >>>>> -            this.target = aTarget;
> >>>>> -            return asBuilder();
> >>>>> -        }
> >>>>> -    }
> >>>>> -
> >>>>> -    /**
> >>>>> -     * Holds data to pass to factory method.
> >>>>> -     */
> >>>>> -    private static class FactoryData {
> >>>>> -        private final Layout<? extends Serializable> layout;
> >>>>> -        private final String name;
> >>>>> -        private final OutputStream os;
> >>>>> -
> >>>>> -        /**
> >>>>> -         * Builds instances.
> >>>>> -         *
> >>>>> -         * @param os
> >>>>> -         *            The OutputStream.
> >>>>> -         * @param type
> >>>>> -         *            The name of the target.
> >>>>> -         * @param layout
> >>>>> -         *            A Serializable layout
> >>>>> -         */
> >>>>> -        public FactoryData(final OutputStream os, final String type,
> >> final Layout<? extends Serializable> layout) {
> >>>>> -            this.os = os;
> >>>>> -            this.name = type;
> >>>>> -            this.layout = layout;
> >>>>> -        }
> >>>>> -    }
> >>>>> -
> >>>>> -    /**
> >>>>> -     * Creates the manager.
> >>>>> -     */
> >>>>> -    private static class OutputStreamManagerFactory implements
> >> ManagerFactory<OutputStreamManager, FactoryData> {
> >>>>> -
> >>>>> -        /**
> >>>>> -         * Creates an OutputStreamManager.
> >>>>> -         *
> >>>>> -         * @param name
> >>>>> -         *            The name of the entity to manage.
> >>>>> -         * @param data
> >>>>> -         *            The data required to create the entity.
> >>>>> -         * @return The OutputStreamManager
> >>>>> -         */
> >>>>> -        @Override
> >>>>> -        public OutputStreamManager createManager(final String name,
> >> final FactoryData data) {
> >>>>> -            return new OutputStreamManager(data.os, data.name,
> >> data.layout, true);
> >>>>> -        }
> >>>>> -    }
> >>>>> -
> >>>>> -    private static OutputStreamManagerFactory factory = new
> >> OutputStreamManagerFactory();
> >>>>> -
> >>>>> -    /**
> >>>>> -     * Creates an OutputStream Appender.
> >>>>> -     *
> >>>>> -     * @param layout
> >>>>> -     *            The layout to use or null to get the default
> layout.
> >>>>> -     * @param filter
> >>>>> -     *            The Filter or null.
> >>>>> -     * @param target
> >>>>> -     *            an output stream.
> >>>>> -     * @param follow
> >>>>> -     *            If true will follow changes to the underlying
> >> output stream.
> >>>>> -     *            Use false as the default.
> >>>>> -     * @param name
> >>>>> -     *            The name of the Appender (required).
> >>>>> -     * @param ignore
> >>>>> -     *            If {@code "true"} (default) exceptions encountered
> >> when
> >>>>> -     *            appending events are logged; otherwise they are
> >> propagated to
> >>>>> -     *            the caller. Use true as the default.
> >>>>> -     * @return The ConsoleAppender.
> >>>>> -     */
> >>>>> -    @PluginFactory
> >>>>> -    public static OutputStreamAppender createAppender(Layout<?
> >> extends Serializable> layout, final Filter filter,
> >>>>> -            final OutputStream target, final String name, final
> >> boolean follow, final boolean ignore) {
> >>>>> -        if (name == null) {
> >>>>> -            LOGGER.error("No name provided for
> OutputStreamAppender");
> >>>>> -            return null;
> >>>>> -        }
> >>>>> -        if (layout == null) {
> >>>>> -            layout = PatternLayout.createDefaultLayout();
> >>>>> -        }
> >>>>> -        return new OutputStreamAppender(name, layout, filter,
> >> getManager(target, follow, layout), ignore, null);
> >>>>> -    }
> >>>>> -
> >>>>> -    private static OutputStreamManager getManager(final OutputStream
> >> target, final boolean follow,
> >>>>> -            final Layout<? extends Serializable> layout) {
> >>>>> -        final OutputStream os = new CloseShieldOutputStream(target);
> >>>>> -        final String managerName = target.getClass().getName() + "@"
> >> + Integer.toHexString(target.hashCode()) + '.'
> >>>>> -                + follow;
> >>>>> -        return OutputStreamManager.getManager(managerName, new
> >> FactoryData(os, managerName, layout), factory);
> >>>>> -    }
> >>>>> -
> >>>>> -    @PluginBuilderFactory
> >>>>> -    public static Builder newBuilder() {
> >>>>> -        return new Builder();
> >>>>> -    }
> >>>>> -
> >>>>> -    private OutputStreamAppender(final String name, final Layout<?
> >> extends Serializable> layout, final Filter filter,
> >>>>> -            final OutputStreamManager manager, final boolean
> >> ignoreExceptions, final Property[] properties) {
> >>>>> -        super(name, layout, filter, ignoreExceptions, true,
> >> properties, manager);
> >>>>> -    }
> >>>>> -
> >>>>> -}
> >>>>> +/*
> >>>>> + * 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.
> >>>>> + */
> >>>>> +package org.apache.logging.log4j.core.appender;
> >>>>> +
> >>>>> +import java.io.OutputStream;
> >>>>> +import java.io.Serializable;
> >>>>> +
> >>>>> +import org.apache.logging.log4j.core.Appender;
> >>>>> +import org.apache.logging.log4j.core.Core;
> >>>>> +import org.apache.logging.log4j.core.Filter;
> >>>>> +import org.apache.logging.log4j.core.Layout;
> >>>>> +import org.apache.logging.log4j.core.config.Property;
> >>>>> +import org.apache.logging.log4j.core.config.plugins.Plugin;
> >>>>> +import
> >> org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
> >>>>> +import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> >>>>> +import org.apache.logging.log4j.core.layout.PatternLayout;
> >>>>> +import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
> >>>>> +import org.apache.logging.log4j.core.util.NullOutputStream;
> >>>>> +
> >>>>> +/**
> >>>>> + * Appends log events to a given output stream using a layout.
> >>>>> + * <p>
> >>>>> + * Character encoding is handled within the Layout.
> >>>>> + * </p>
> >>>>> + */
> >>>>> +@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME,
> >> elementType = Appender.ELEMENT_TYPE, printObject = true)
> >>>>> +public final class OutputStreamAppender extends
> >> AbstractOutputStreamAppender<OutputStreamManager> {
> >>>>> +
> >>>>> +    /**
> >>>>> +     * Builds OutputStreamAppender instances.
> >>>>> +     *
> >>>>> +     * @param <B>
> >>>>> +     *            The type to build.
> >>>>> +     */
> >>>>> +    public static class Builder<B extends Builder<B>> extends
> >> AbstractOutputStreamAppender.Builder<B>
> >>>>> +            implements
> >> org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
> >>>>> +
> >>>>> +        private boolean follow = false;
> >>>>> +
> >>>>> +        private final boolean ignoreExceptions = true;
> >>>>> +
> >>>>> +        private OutputStream target;
> >>>>> +
> >>>>> +        @Override
> >>>>> +        public OutputStreamAppender build() {
> >>>>> +            final Layout<? extends Serializable> layout =
> getLayout();
> >>>>> +            final Layout<? extends Serializable> actualLayout =
> >> layout == null ? PatternLayout.createDefaultLayout()
> >>>>> +                    : layout;
> >>>>> +            return new OutputStreamAppender(getName(), actualLayout,
> >> getFilter(), getManager(target, follow, actualLayout),
> >>>>> +                    ignoreExceptions, getPropertyArray());
> >>>>> +        }
> >>>>> +
> >>>>> +        public B setFollow(final boolean shouldFollow) {
> >>>>> +            this.follow = shouldFollow;
> >>>>> +            return asBuilder();
> >>>>> +        }
> >>>>> +
> >>>>> +        public B setTarget(final OutputStream aTarget) {
> >>>>> +            this.target = aTarget;
> >>>>> +            return asBuilder();
> >>>>> +        }
> >>>>> +    }
> >>>>> +
> >>>>> +    /**
> >>>>> +     * Holds data to pass to factory method.
> >>>>> +     */
> >>>>> +    private static class FactoryData {
> >>>>> +        private final Layout<? extends Serializable> layout;
> >>>>> +        private final String name;
> >>>>> +        private final OutputStream os;
> >>>>> +
> >>>>> +        /**
> >>>>> +         * Builds instances.
> >>>>> +         *
> >>>>> +         * @param os
> >>>>> +         *            The OutputStream.
> >>>>> +         * @param type
> >>>>> +         *            The name of the target.
> >>>>> +         * @param layout
> >>>>> +         *            A Serializable layout
> >>>>> +         */
> >>>>> +        public FactoryData(final OutputStream os, final String type,
> >> final Layout<? extends Serializable> layout) {
> >>>>> +            this.os = os;
> >>>>> +            this.name = type;
> >>>>> +            this.layout = layout;
> >>>>> +        }
> >>>>> +    }
> >>>>> +
> >>>>> +    /**
> >>>>> +     * Creates the manager.
> >>>>> +     */
> >>>>> +    private static class OutputStreamManagerFactory implements
> >> ManagerFactory<OutputStreamManager, FactoryData> {
> >>>>> +
> >>>>> +        /**
> >>>>> +         * Creates an OutputStreamManager.
> >>>>> +         *
> >>>>> +         * @param name
> >>>>> +         *            The name of the entity to manage.
> >>>>> +         * @param data
> >>>>> +         *            The data required to create the entity.
> >>>>> +         * @return The OutputStreamManager
> >>>>> +         */
> >>>>> +        @Override
> >>>>> +        public OutputStreamManager createManager(final String name,
> >> final FactoryData data) {
> >>>>> +            return new OutputStreamManager(data.os, data.name,
> >> data.layout, true);
> >>>>> +        }
> >>>>> +    }
> >>>>> +
> >>>>> +    private static OutputStreamManagerFactory factory = new
> >> OutputStreamManagerFactory();
> >>>>> +
> >>>>> +    /**
> >>>>> +     * Creates an OutputStream Appender.
> >>>>> +     *
> >>>>> +     * @param layout
> >>>>> +     *            The layout to use or null to get the default
> layout.
> >>>>> +     * @param filter
> >>>>> +     *            The Filter or null.
> >>>>> +     * @param target
> >>>>> +     *            an output stream.
> >>>>> +     * @param follow
> >>>>> +     *            If true will follow changes to the underlying
> >> output stream.
> >>>>> +     *            Use false as the default.
> >>>>> +     * @param name
> >>>>> +     *            The name of the Appender (required).
> >>>>> +     * @param ignore
> >>>>> +     *            If {@code "true"} (default) exceptions encountered
> >> when
> >>>>> +     *            appending events are logged; otherwise they are
> >> propagated to
> >>>>> +     *            the caller. Use true as the default.
> >>>>> +     * @return The ConsoleAppender.
> >>>>> +     */
> >>>>> +    @PluginFactory
> >>>>> +    public static OutputStreamAppender createAppender(Layout<?
> >> extends Serializable> layout, final Filter filter,
> >>>>> +            final OutputStream target, final String name, final
> >> boolean follow, final boolean ignore) {
> >>>>> +        if (name == null) {
> >>>>> +            LOGGER.error("No name provided for
> OutputStreamAppender");
> >>>>> +            return null;
> >>>>> +        }
> >>>>> +        if (layout == null) {
> >>>>> +            layout = PatternLayout.createDefaultLayout();
> >>>>> +        }
> >>>>> +        return new OutputStreamAppender(name, layout, filter,
> >> getManager(target, follow, layout), ignore, null);
> >>>>> +    }
> >>>>> +
> >>>>> +    private static OutputStreamManager getManager(final OutputStream
> >> target, final boolean follow,
> >>>>> +            final Layout<? extends Serializable> layout) {
> >>>>> +        final OutputStream os = target == null ?
> >> NullOutputStream.getInstance() : new CloseShieldOutputStream(target);
> >>>>> +        final OutputStream targetRef = target == null ? os : target;
> >>>>> +        final String managerName = targetRef.getClass().getName() +
> >> "@" + Integer.toHexString(targetRef.hashCode())
> >>>>> +                + '.' + follow;
> >>>>> +        return OutputStreamManager.getManager(managerName, new
> >> FactoryData(os, managerName, layout), factory);
> >>>>> +    }
> >>>>> +
> >>>>> +    @PluginBuilderFactory
> >>>>> +    public static <B extends Builder<B>> B newBuilder() {
> >>>>> +        return new Builder<B>().asBuilder();
> >>>>> +    }
> >>>>> +
> >>>>> +    private OutputStreamAppender(final String name, final Layout<?
> >> extends Serializable> layout, final Filter filter,
> >>>>> +            final OutputStreamManager manager, final boolean
> >> ignoreExceptions, final Property[] properties) {
> >>>>> +        super(name, layout, filter, ignoreExceptions, true,
> >> properties, manager);
> >>>>> +    }
> >>>>> +
> >>>>> +}
> >>>>> diff --git
> >>
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>
> b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>>>> index 00af014..c1448bf 100644
> >>>>> ---
> >>
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>>>> +++
> >>
> b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>>>> @@ -1,108 +1,122 @@
> >>>>> -/*
> >>>>> - * 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.
> >>>>> - */
> >>>>> -package org.apache.logging.log4j.core.appender;
> >>>>> -
> >>>>> -import java.io.BufferedOutputStream;
> >>>>> -import java.io.ByteArrayOutputStream;
> >>>>> -import java.io.OutputStream;
> >>>>> -import java.sql.SQLException;
> >>>>> -
> >>>>> -import org.apache.logging.log4j.LogManager;
> >>>>> -import org.apache.logging.log4j.Logger;
> >>>>> -import org.apache.logging.log4j.core.Appender;
> >>>>> -import org.apache.logging.log4j.core.LoggerContext;
> >>>>> -import org.apache.logging.log4j.core.config.Configuration;
> >>>>> -import org.apache.logging.log4j.core.layout.PatternLayout;
> >>>>> -import org.junit.Assert;
> >>>>> -import org.junit.Rule;
> >>>>> -import org.junit.Test;
> >>>>> -import org.junit.rules.TestName;
> >>>>> -
> >>>>> -/**
> >>>>> - * Tests {@link OutputStreamAppender}.
> >>>>> - */
> >>>>> -public class OutputStreamAppenderTest {
> >>>>> -
> >>>>> -    private static final String TEST_MSG = "FOO ERROR";
> >>>>> -
> >>>>> -    @Rule
> >>>>> -    public TestName testName = new TestName();
> >>>>> -
> >>>>> -    private String getName(final OutputStream out) {
> >>>>> -        return out.getClass().getSimpleName() + "." +
> >> testName.getMethodName();
> >>>>> -    }
> >>>>> -
> >>>>> -    /**
> >>>>> -     * Tests that you can add an output stream appender dynamically.
> >>>>> -     */
> >>>>> -    private void addAppender(final OutputStream outputStream, final
> >> String outputStreamName) {
> >>>>> -        final LoggerContext context =
> LoggerContext.getContext(false);
> >>>>> -        final Configuration config = context.getConfiguration();
> >>>>> -        final PatternLayout layout =
> >> PatternLayout.createDefaultLayout(config);
> >>>>> -        final Appender appender =
> >> OutputStreamAppender.createAppender(layout, null, outputStream,
> >> outputStreamName, false, true);
> >>>>> -        appender.start();
> >>>>> -        config.addAppender(appender);
> >>>>> -        ConfigurationTestUtils.updateLoggers(appender, config);
> >>>>> -    }
> >>>>> -
> >>>>> -    @Test
> >>>>> -    public void testOutputStreamAppenderToBufferedOutputStream()
> >> throws SQLException {
> >>>>> -        final ByteArrayOutputStream out = new
> ByteArrayOutputStream();
> >>>>> -        final OutputStream os = new BufferedOutputStream(out);
> >>>>> -        final String name = getName(out);
> >>>>> -        final Logger logger = LogManager.getLogger(name);
> >>>>> -        addAppender(os, name);
> >>>>> -        logger.error(TEST_MSG);
> >>>>> -        final String actual = out.toString();
> >>>>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>>>> -    }
> >>>>> -
> >>>>> -    @Test
> >>>>> -    public void testOutputStreamAppenderToByteArrayOutputStream()
> >> throws SQLException {
> >>>>> -        final OutputStream out = new ByteArrayOutputStream();
> >>>>> -        final String name = getName(out);
> >>>>> -        final Logger logger = LogManager.getLogger(name);
> >>>>> -        addAppender(out, name);
> >>>>> -        logger.error(TEST_MSG);
> >>>>> -        final String actual = out.toString();
> >>>>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>>>> -    }
> >>>>> -
> >>>>> -    /**
> >>>>> -     * Validates that the code pattern we use to add an appender on
> >> the fly
> >>>>> -     * works with a basic appender that is not the new OutputStream
> >> appender or
> >>>>> -     * new Writer appender.
> >>>>> -     */
> >>>>> -    @Test
> >>>>> -    public void testUpdatePatternWithFileAppender() {
> >>>>> -        final LoggerContext ctx = (LoggerContext)
> >> LogManager.getContext(false);
> >>>>> -        final Configuration config = ctx.getConfiguration();
> >>>>> -        // @formatter:off
> >>>>> -        final Appender appender = FileAppender.newBuilder()
> >>>>> -        .withFileName("target/" + getClass().getName() + ".log")
> >>>>> -
> .withAppend(false).setName("File").setIgnoreExceptions(false)
> >>>>> -            .withBufferedIo(false)
> >>>>> -            .withBufferSize(4000)
> >>>>> -            .setConfiguration(config)
> >>>>> -            .build();
> >>>>> -        // @formatter:on
> >>>>> -        appender.start();
> >>>>> -        config.addAppender(appender);
> >>>>> -        ConfigurationTestUtils.updateLoggers(appender, config);
> >>>>> -        LogManager.getLogger().error("FOO MSG");
> >>>>> -    }
> >>>>> -}
> >>>>> +/*
> >>>>> + * 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.
> >>>>> + */
> >>>>> +package org.apache.logging.log4j.core.appender;
> >>>>> +
> >>>>> +import java.io.BufferedOutputStream;
> >>>>> +import java.io.ByteArrayOutputStream;
> >>>>> +import java.io.OutputStream;
> >>>>> +import java.sql.SQLException;
> >>>>> +
> >>>>> +import org.apache.logging.log4j.LogManager;
> >>>>> +import org.apache.logging.log4j.Logger;
> >>>>> +import org.apache.logging.log4j.core.Appender;
> >>>>> +import org.apache.logging.log4j.core.LoggerContext;
> >>>>> +import org.apache.logging.log4j.core.config.Configuration;
> >>>>> +import org.apache.logging.log4j.core.filter.NoMarkerFilter;
> >>>>> +import org.apache.logging.log4j.core.layout.PatternLayout;
> >>>>> +import org.junit.Assert;
> >>>>> +import org.junit.Rule;
> >>>>> +import org.junit.Test;
> >>>>> +import org.junit.rules.TestName;
> >>>>> +
> >>>>> +/**
> >>>>> + * Tests {@link OutputStreamAppender}.
> >>>>> + */
> >>>>> +public class OutputStreamAppenderTest {
> >>>>> +
> >>>>> +    private static final String TEST_MSG = "FOO ERROR";
> >>>>> +
> >>>>> +    @Rule
> >>>>> +    public TestName testName = new TestName();
> >>>>> +
> >>>>> +    private String getName(final OutputStream out) {
> >>>>> +        return out.getClass().getSimpleName() + "." +
> >> testName.getMethodName();
> >>>>> +    }
> >>>>> +
> >>>>> +    /**
> >>>>> +     * Tests that you can add an output stream appender dynamically.
> >>>>> +     */
> >>>>> +    private void addAppender(final OutputStream outputStream, final
> >> String outputStreamName) {
> >>>>> +        final LoggerContext context =
> LoggerContext.getContext(false);
> >>>>> +        final Configuration config = context.getConfiguration();
> >>>>> +        final PatternLayout layout =
> >> PatternLayout.createDefaultLayout(config);
> >>>>> +        final Appender appender =
> >> OutputStreamAppender.createAppender(layout, null, outputStream,
> >> outputStreamName, false, true);
> >>>>> +        appender.start();
> >>>>> +        config.addAppender(appender);
> >>>>> +        ConfigurationTestUtils.updateLoggers(appender, config);
> >>>>> +    }
> >>>>> +
> >>>>> +    @Test
> >>>>> +    public void testBuildFilter() {
> >>>>> +        final NoMarkerFilter filter =
> >> NoMarkerFilter.newBuilder().build();
> >>>>> +        // @formatter:off
> >>>>> +        final OutputStreamAppender.Builder builder =
> >> OutputStreamAppender.newBuilder()
> >>>>> +                .setName("test")
> >>>>> +                .setFilter(filter);
> >>>>> +        // @formatter:on
> >>>>> +        Assert.assertEquals(filter, builder.getFilter());
> >>>>> +        final OutputStreamAppender appender = builder.build();
> >>>>> +        Assert.assertEquals(filter, appender.getFilter());
> >>>>> +    }
> >>>>> +
> >>>>> +    @Test
> >>>>> +    public void testOutputStreamAppenderToBufferedOutputStream()
> >> throws SQLException {
> >>>>> +        final ByteArrayOutputStream out = new
> ByteArrayOutputStream();
> >>>>> +        final OutputStream os = new BufferedOutputStream(out);
> >>>>> +        final String name = getName(out);
> >>>>> +        final Logger logger = LogManager.getLogger(name);
> >>>>> +        addAppender(os, name);
> >>>>> +        logger.error(TEST_MSG);
> >>>>> +        final String actual = out.toString();
> >>>>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>>>> +    }
> >>>>> +
> >>>>> +    @Test
> >>>>> +    public void testOutputStreamAppenderToByteArrayOutputStream()
> >> throws SQLException {
> >>>>> +        final OutputStream out = new ByteArrayOutputStream();
> >>>>> +        final String name = getName(out);
> >>>>> +        final Logger logger = LogManager.getLogger(name);
> >>>>> +        addAppender(out, name);
> >>>>> +        logger.error(TEST_MSG);
> >>>>> +        final String actual = out.toString();
> >>>>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>>>> +    }
> >>>>> +
> >>>>> +    /**
> >>>>> +     * Validates that the code pattern we use to add an appender on
> >> the fly
> >>>>> +     * works with a basic appender that is not the new OutputStream
> >> appender or
> >>>>> +     * new Writer appender.
> >>>>> +     */
> >>>>> +    @Test
> >>>>> +    public void testUpdatePatternWithFileAppender() {
> >>>>> +        final LoggerContext ctx = (LoggerContext)
> >> LogManager.getContext(false);
> >>>>> +        final Configuration config = ctx.getConfiguration();
> >>>>> +        // @formatter:off
> >>>>> +        final Appender appender = FileAppender.newBuilder()
> >>>>> +        .withFileName("target/" + getClass().getName() + ".log")
> >>>>> +
> .withAppend(false).setName("File").setIgnoreExceptions(false)
> >>>>> +            .withBufferedIo(false)
> >>>>> +            .withBufferSize(4000)
> >>>>> +            .setConfiguration(config)
> >>>>> +            .build();
> >>>>> +        // @formatter:on
> >>>>> +        appender.start();
> >>>>> +        config.addAppender(appender);
> >>>>> +        ConfigurationTestUtils.updateLoggers(appender, config);
> >>>>> +        LogManager.getLogger().error("FOO MSG");
> >>>>> +    }
> >>>>> +}
> >>>>> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
> >>>>> index c3483bd..a9ec160 100644
> >>>>> --- a/src/changes/changes.xml
> >>>>> +++ b/src/changes/changes.xml
> >>>>> @@ -33,6 +33,9 @@
> >>>>>    <action issue="LOG4J2-2639" dev="rgoers" type="add">
> >>>>>      Add builder pattern to Logger interface.
> >>>>>    </action>
> >>>>> +      <action issue="LOG4J2-2673" dev="ggregory" type="fix"
> >> due-to="Yuichi Sugimura, Gary Gregory">
> >>>>> +        OutputStreamAppender.Builder ignores setFilter().
> >>>>> +      </action>
> >>>>>  </release>
> >>>>>  <release version="2.12.1" date="2019-08-06" description="GA Release
> >> 2.12.1">
> >>>>>    <action issue="LOG4J2-1946" dev="rgoers" type="fix" due-to="Igor
> >> Perelyotov">
> >>>>>
> >>>>>
> >>>>
> >>>>
> >>>>
> >>>
> >>>
> >>>
> >>
> >>
> >>
>
>
>

Re: [logging-log4j2] branch release-2.x updated: [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().

Posted by Matt Sicker <bo...@gmail.com>.
Thanks Gary!

On Fri, Aug 16, 2019 at 23:41, Gary Gregory <ga...@gmail.com> wrote:

> Check. I updated the RevApi config.
>
> Gary
>
> On Fri, Aug 16, 2019 at 1:30 PM Ralph Goers <ra...@dslextreme.com>
> wrote:
>
> > You may not be missing anything. If you don’t think it is a problem then
> > just add the config items revapi spits out to the configuration. There
> are
> > some there already so you can look at the justifications for those as
> > examples.
> >
> > Ralph
> >
> > > On Aug 16, 2019, at 11:23 AM, Gary Gregory <ga...@gmail.com>
> > wrote:
> > >
> > > It looks like a bug in revapi to me: it does not know about type
> > erasures.
> > > I created a new Maven project that depends on Log4j Core 2.12.1 with:
> > >
> > > public class App
> > > {
> > >    public static void main( String[] args )
> > >    {
> > >        System.out.println( "Hello World!" );
> > >        Builder builder = OutputStreamAppender.newBuilder();
> > >    }
> > > }
> > >
> > > Then I ran that class against 2.13.-SNAPSHOT Core without recompiling
> and
> > > it ran fine.
> > >
> > > What am I missing?
> > >
> > > Gary
> > >
> > > On Thu, Aug 15, 2019 at 5:03 PM Ralph Goers <
> ralph.goers@dslextreme.com>
> > > wrote:
> > >
> > >> I believe you have not read this thread. I am not talking about the
> bug
> > >> you fixed. I am talking the compatibility breakage you created.
> > >>
> > >> 1. The backward compatibility breakage only occurred on the
> release-2.x
> > >> branch because revapi is essentially disabled on master. Too much has
> > >> changed to bother keeping track.
> > >> 2. I haven’t seen any commit messages indicating you committed
> anything
> > to
> > >> fix this.
> > >> 3. The build is still failing for me.  Try running mvn clean install
> > >> -DskipTests in log4j-core. It will break for you too.
> > >>
> > >> Please look at the Jenkins build and fix the problems by either
> > reverting
> > >> the breakage or by adding the recommended changes to revapi.json to
> > >> document why compatibility was broken.
> > >>
> > >> Ralph
> > >>
> > >>
> > >>> On Aug 15, 2019, at 4:54 PM, Gary Gregory <ga...@gmail.com>
> > >> wrote:
> > >>>
> > >>> I fixed it already in both branches.
> > >>>
> > >>> Gary
> > >>>
> > >>> On Thu, Aug 15, 2019, 10:42 Ralph Goers <ra...@dslextreme.com>
> > >> wrote:
> > >>>
> > >>>> Gary,
> > >>>>
> > >>>> Are you going to look into this?
> > >>>>
> > >>>> Ralph
> > >>>>
> > >>>>> On Aug 14, 2019, at 9:17 AM, Ralph Goers <
> ralph.goers@dslextreme.com
> > >
> > >>>> wrote:
> > >>>>>
> > >>>>> Any update on this? I’d like my builds to work again.
> > >>>>>
> > >>>>> Ralph
> > >>>>>
> > >>>>>> On Aug 13, 2019, at 4:29 PM, Ralph Goers <
> > ralph.goers@dslextreme.com>
> > >>>> wrote:
> > >>>>>>
> > >>>>>> Gary,
> > >>>>>>
> > >>>>>> It seems this change broker compatibility. Please see the Jenkins
> > >>>> failure. You either need to resolve the code so compatibility is
> > >> maintained
> > >>>> or update revapi.json with the recommended changes.
> > >>>>>>
> > >>>>>> Ralph
> > >>>>>>
> > >>>>>>> On Aug 13, 2019, at 2:06 PM, ggregory@apache.org wrote:
> > >>>>>>>
> > >>>>>>> This is an automated email from the ASF dual-hosted git
> repository.
> > >>>>>>>
> > >>>>>>> ggregory pushed a commit to branch release-2.x
> > >>>>>>> in repository
> > https://gitbox.apache.org/repos/asf/logging-log4j2.git
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> The following commit(s) were added to refs/heads/release-2.x by
> > this
> > >>>> push:
> > >>>>>>> new 4679a08  [LOG4J2-2673] OutputStreamAppender.Builder ignores
> > >>>> setFilter().
> > >>>>>>> 4679a08 is described below
> > >>>>>>>
> > >>>>>>> commit 4679a08d4899350f7ee19d050d2a96783b748066
> > >>>>>>> Author: Gary Gregory <ga...@gmail.com>
> > >>>>>>> AuthorDate: Tue Aug 13 17:06:48 2019 -0400
> > >>>>>>>
> > >>>>>>> [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
> > >>>>>>>
> > >>>>>>> Also allow a null output stream for convenience instead of an
> NPE.
> > >>>>>>> ---
> > >>>>>>> .../log4j/core/appender/OutputStreamAppender.java  | 351
> > >>>> +++++++++++----------
> > >>>>>>> .../core/appender/OutputStreamAppenderTest.java    | 230
> > >> +++++++-------
> > >>>>>>> src/changes/changes.xml                            |   3 +
> > >>>>>>> 3 files changed, 302 insertions(+), 282 deletions(-)
> > >>>>>>>
> > >>>>>>> diff --git
> > >>>>
> > >>
> >
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> > >>>>
> > >>
> >
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> > >>>>>>> index 7dfd187..dc6f352 100644
> > >>>>>>> ---
> > >>>>
> > >>
> >
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> > >>>>>>> +++
> > >>>>
> > >>
> >
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> > >>>>>>> @@ -1,174 +1,177 @@
> > >>>>>>> -/*
> > >>>>>>> - * 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.
> > >>>>>>> - */
> > >>>>>>> -package org.apache.logging.log4j.core.appender;
> > >>>>>>> -
> > >>>>>>> -import java.io.OutputStream;
> > >>>>>>> -import java.io.Serializable;
> > >>>>>>> -
> > >>>>>>> -import org.apache.logging.log4j.core.Appender;
> > >>>>>>> -import org.apache.logging.log4j.core.Core;
> > >>>>>>> -import org.apache.logging.log4j.core.Filter;
> > >>>>>>> -import org.apache.logging.log4j.core.Layout;
> > >>>>>>> -import org.apache.logging.log4j.core.config.Property;
> > >>>>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> > >>>>>>> -import
> > >>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
> > >>>>>>> -import
> org.apache.logging.log4j.core.config.plugins.PluginFactory;
> > >>>>>>> -import org.apache.logging.log4j.core.layout.PatternLayout;
> > >>>>>>> -import
> org.apache.logging.log4j.core.util.CloseShieldOutputStream;
> > >>>>>>> -
> > >>>>>>> -/**
> > >>>>>>> - * Appends log events to a given output stream using a layout.
> > >>>>>>> - * <p>
> > >>>>>>> - * Character encoding is handled within the Layout.
> > >>>>>>> - * </p>
> > >>>>>>> - */
> > >>>>>>> -@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME,
> > >>>> elementType = Appender.ELEMENT_TYPE, printObject = true)
> > >>>>>>> -public final class OutputStreamAppender extends
> > >>>> AbstractOutputStreamAppender<OutputStreamManager> {
> > >>>>>>> -
> > >>>>>>> -    /**
> > >>>>>>> -     * Builds OutputStreamAppender instances.
> > >>>>>>> -     */
> > >>>>>>> -    public static class Builder<B extends Builder<B>> extends
> > >>>> AbstractOutputStreamAppender.Builder<B>
> > >>>>>>> -            implements
> > >>>> org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
> > >>>>>>> -
> > >>>>>>> -        private Filter filter;
> > >>>>>>> -
> > >>>>>>> -        private boolean follow = false;
> > >>>>>>> -
> > >>>>>>> -        private final boolean ignoreExceptions = true;
> > >>>>>>> -
> > >>>>>>> -        private OutputStream target;
> > >>>>>>> -
> > >>>>>>> -        @Override
> > >>>>>>> -        public OutputStreamAppender build() {
> > >>>>>>> -            final Layout<? extends Serializable> layout =
> > >> getLayout();
> > >>>>>>> -            final Layout<? extends Serializable> actualLayout =
> > >>>> layout == null ? PatternLayout.createDefaultLayout()
> > >>>>>>> -                    : layout;
> > >>>>>>> -            return new OutputStreamAppender(getName(),
> > actualLayout,
> > >>>> filter, getManager(target, follow, actualLayout),
> > >>>>>>> -                    ignoreExceptions, getPropertyArray());
> > >>>>>>> -        }
> > >>>>>>> -
> > >>>>>>> -        public B setFollow(final boolean shouldFollow) {
> > >>>>>>> -            this.follow = shouldFollow;
> > >>>>>>> -            return asBuilder();
> > >>>>>>> -        }
> > >>>>>>> -
> > >>>>>>> -        public B setTarget(final OutputStream aTarget) {
> > >>>>>>> -            this.target = aTarget;
> > >>>>>>> -            return asBuilder();
> > >>>>>>> -        }
> > >>>>>>> -    }
> > >>>>>>> -
> > >>>>>>> -    /**
> > >>>>>>> -     * Holds data to pass to factory method.
> > >>>>>>> -     */
> > >>>>>>> -    private static class FactoryData {
> > >>>>>>> -        private final Layout<? extends Serializable> layout;
> > >>>>>>> -        private final String name;
> > >>>>>>> -        private final OutputStream os;
> > >>>>>>> -
> > >>>>>>> -        /**
> > >>>>>>> -         * Builds instances.
> > >>>>>>> -         *
> > >>>>>>> -         * @param os
> > >>>>>>> -         *            The OutputStream.
> > >>>>>>> -         * @param type
> > >>>>>>> -         *            The name of the target.
> > >>>>>>> -         * @param layout
> > >>>>>>> -         *            A Serializable layout
> > >>>>>>> -         */
> > >>>>>>> -        public FactoryData(final OutputStream os, final String
> > type,
> > >>>> final Layout<? extends Serializable> layout) {
> > >>>>>>> -            this.os = os;
> > >>>>>>> -            this.name = type;
> > >>>>>>> -            this.layout = layout;
> > >>>>>>> -        }
> > >>>>>>> -    }
> > >>>>>>> -
> > >>>>>>> -    /**
> > >>>>>>> -     * Creates the manager.
> > >>>>>>> -     */
> > >>>>>>> -    private static class OutputStreamManagerFactory implements
> > >>>> ManagerFactory<OutputStreamManager, FactoryData> {
> > >>>>>>> -
> > >>>>>>> -        /**
> > >>>>>>> -         * Creates an OutputStreamManager.
> > >>>>>>> -         *
> > >>>>>>> -         * @param name
> > >>>>>>> -         *            The name of the entity to manage.
> > >>>>>>> -         * @param data
> > >>>>>>> -         *            The data required to create the entity.
> > >>>>>>> -         * @return The OutputStreamManager
> > >>>>>>> -         */
> > >>>>>>> -        @Override
> > >>>>>>> -        public OutputStreamManager createManager(final String
> > name,
> > >>>> final FactoryData data) {
> > >>>>>>> -            return new OutputStreamManager(data.os, data.name,
> > >>>> data.layout, true);
> > >>>>>>> -        }
> > >>>>>>> -    }
> > >>>>>>> -
> > >>>>>>> -    private static OutputStreamManagerFactory factory = new
> > >>>> OutputStreamManagerFactory();
> > >>>>>>> -
> > >>>>>>> -    /**
> > >>>>>>> -     * Creates an OutputStream Appender.
> > >>>>>>> -     *
> > >>>>>>> -     * @param layout
> > >>>>>>> -     *            The layout to use or null to get the default
> > >> layout.
> > >>>>>>> -     * @param filter
> > >>>>>>> -     *            The Filter or null.
> > >>>>>>> -     * @param target
> > >>>>>>> -     *            an output stream.
> > >>>>>>> -     * @param follow
> > >>>>>>> -     *            If true will follow changes to the underlying
> > >>>> output stream.
> > >>>>>>> -     *            Use false as the default.
> > >>>>>>> -     * @param name
> > >>>>>>> -     *            The name of the Appender (required).
> > >>>>>>> -     * @param ignore
> > >>>>>>> -     *            If {@code "true"} (default) exceptions
> > encountered
> > >>>> when
> > >>>>>>> -     *            appending events are logged; otherwise they
> are
> > >>>> propagated to
> > >>>>>>> -     *            the caller. Use true as the default.
> > >>>>>>> -     * @return The ConsoleAppender.
> > >>>>>>> -     */
> > >>>>>>> -    @PluginFactory
> > >>>>>>> -    public static OutputStreamAppender createAppender(Layout<?
> > >>>> extends Serializable> layout, final Filter filter,
> > >>>>>>> -            final OutputStream target, final String name, final
> > >>>> boolean follow, final boolean ignore) {
> > >>>>>>> -        if (name == null) {
> > >>>>>>> -            LOGGER.error("No name provided for
> > >> OutputStreamAppender");
> > >>>>>>> -            return null;
> > >>>>>>> -        }
> > >>>>>>> -        if (layout == null) {
> > >>>>>>> -            layout = PatternLayout.createDefaultLayout();
> > >>>>>>> -        }
> > >>>>>>> -        return new OutputStreamAppender(name, layout, filter,
> > >>>> getManager(target, follow, layout), ignore, null);
> > >>>>>>> -    }
> > >>>>>>> -
> > >>>>>>> -    private static OutputStreamManager getManager(final
> > OutputStream
> > >>>> target, final boolean follow,
> > >>>>>>> -            final Layout<? extends Serializable> layout) {
> > >>>>>>> -        final OutputStream os = new
> > CloseShieldOutputStream(target);
> > >>>>>>> -        final String managerName = target.getClass().getName() +
> > "@"
> > >>>> + Integer.toHexString(target.hashCode()) + '.'
> > >>>>>>> -                + follow;
> > >>>>>>> -        return OutputStreamManager.getManager(managerName, new
> > >>>> FactoryData(os, managerName, layout), factory);
> > >>>>>>> -    }
> > >>>>>>> -
> > >>>>>>> -    @PluginBuilderFactory
> > >>>>>>> -    public static Builder newBuilder() {
> > >>>>>>> -        return new Builder();
> > >>>>>>> -    }
> > >>>>>>> -
> > >>>>>>> -    private OutputStreamAppender(final String name, final
> Layout<?
> > >>>> extends Serializable> layout, final Filter filter,
> > >>>>>>> -            final OutputStreamManager manager, final boolean
> > >>>> ignoreExceptions, final Property[] properties) {
> > >>>>>>> -        super(name, layout, filter, ignoreExceptions, true,
> > >>>> properties, manager);
> > >>>>>>> -    }
> > >>>>>>> -
> > >>>>>>> -}
> > >>>>>>> +/*
> > >>>>>>> + * 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.
> > >>>>>>> + */
> > >>>>>>> +package org.apache.logging.log4j.core.appender;
> > >>>>>>> +
> > >>>>>>> +import java.io.OutputStream;
> > >>>>>>> +import java.io.Serializable;
> > >>>>>>> +
> > >>>>>>> +import org.apache.logging.log4j.core.Appender;
> > >>>>>>> +import org.apache.logging.log4j.core.Core;
> > >>>>>>> +import org.apache.logging.log4j.core.Filter;
> > >>>>>>> +import org.apache.logging.log4j.core.Layout;
> > >>>>>>> +import org.apache.logging.log4j.core.config.Property;
> > >>>>>>> +import org.apache.logging.log4j.core.config.plugins.Plugin;
> > >>>>>>> +import
> > >>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
> > >>>>>>> +import
> org.apache.logging.log4j.core.config.plugins.PluginFactory;
> > >>>>>>> +import org.apache.logging.log4j.core.layout.PatternLayout;
> > >>>>>>> +import
> org.apache.logging.log4j.core.util.CloseShieldOutputStream;
> > >>>>>>> +import org.apache.logging.log4j.core.util.NullOutputStream;
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> + * Appends log events to a given output stream using a layout.
> > >>>>>>> + * <p>
> > >>>>>>> + * Character encoding is handled within the Layout.
> > >>>>>>> + * </p>
> > >>>>>>> + */
> > >>>>>>> +@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME,
> > >>>> elementType = Appender.ELEMENT_TYPE, printObject = true)
> > >>>>>>> +public final class OutputStreamAppender extends
> > >>>> AbstractOutputStreamAppender<OutputStreamManager> {
> > >>>>>>> +
> > >>>>>>> +    /**
> > >>>>>>> +     * Builds OutputStreamAppender instances.
> > >>>>>>> +     *
> > >>>>>>> +     * @param <B>
> > >>>>>>> +     *            The type to build.
> > >>>>>>> +     */
> > >>>>>>> +    public static class Builder<B extends Builder<B>> extends
> > >>>> AbstractOutputStreamAppender.Builder<B>
> > >>>>>>> +            implements
> > >>>> org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
> > >>>>>>> +
> > >>>>>>> +        private boolean follow = false;
> > >>>>>>> +
> > >>>>>>> +        private final boolean ignoreExceptions = true;
> > >>>>>>> +
> > >>>>>>> +        private OutputStream target;
> > >>>>>>> +
> > >>>>>>> +        @Override
> > >>>>>>> +        public OutputStreamAppender build() {
> > >>>>>>> +            final Layout<? extends Serializable> layout =
> > >> getLayout();
> > >>>>>>> +            final Layout<? extends Serializable> actualLayout =
> > >>>> layout == null ? PatternLayout.createDefaultLayout()
> > >>>>>>> +                    : layout;
> > >>>>>>> +            return new OutputStreamAppender(getName(),
> > actualLayout,
> > >>>> getFilter(), getManager(target, follow, actualLayout),
> > >>>>>>> +                    ignoreExceptions, getPropertyArray());
> > >>>>>>> +        }
> > >>>>>>> +
> > >>>>>>> +        public B setFollow(final boolean shouldFollow) {
> > >>>>>>> +            this.follow = shouldFollow;
> > >>>>>>> +            return asBuilder();
> > >>>>>>> +        }
> > >>>>>>> +
> > >>>>>>> +        public B setTarget(final OutputStream aTarget) {
> > >>>>>>> +            this.target = aTarget;
> > >>>>>>> +            return asBuilder();
> > >>>>>>> +        }
> > >>>>>>> +    }
> > >>>>>>> +
> > >>>>>>> +    /**
> > >>>>>>> +     * Holds data to pass to factory method.
> > >>>>>>> +     */
> > >>>>>>> +    private static class FactoryData {
> > >>>>>>> +        private final Layout<? extends Serializable> layout;
> > >>>>>>> +        private final String name;
> > >>>>>>> +        private final OutputStream os;
> > >>>>>>> +
> > >>>>>>> +        /**
> > >>>>>>> +         * Builds instances.
> > >>>>>>> +         *
> > >>>>>>> +         * @param os
> > >>>>>>> +         *            The OutputStream.
> > >>>>>>> +         * @param type
> > >>>>>>> +         *            The name of the target.
> > >>>>>>> +         * @param layout
> > >>>>>>> +         *            A Serializable layout
> > >>>>>>> +         */
> > >>>>>>> +        public FactoryData(final OutputStream os, final String
> > type,
> > >>>> final Layout<? extends Serializable> layout) {
> > >>>>>>> +            this.os = os;
> > >>>>>>> +            this.name = type;
> > >>>>>>> +            this.layout = layout;
> > >>>>>>> +        }
> > >>>>>>> +    }
> > >>>>>>> +
> > >>>>>>> +    /**
> > >>>>>>> +     * Creates the manager.
> > >>>>>>> +     */
> > >>>>>>> +    private static class OutputStreamManagerFactory implements
> > >>>> ManagerFactory<OutputStreamManager, FactoryData> {
> > >>>>>>> +
> > >>>>>>> +        /**
> > >>>>>>> +         * Creates an OutputStreamManager.
> > >>>>>>> +         *
> > >>>>>>> +         * @param name
> > >>>>>>> +         *            The name of the entity to manage.
> > >>>>>>> +         * @param data
> > >>>>>>> +         *            The data required to create the entity.
> > >>>>>>> +         * @return The OutputStreamManager
> > >>>>>>> +         */
> > >>>>>>> +        @Override
> > >>>>>>> +        public OutputStreamManager createManager(final String
> > name,
> > >>>> final FactoryData data) {
> > >>>>>>> +            return new OutputStreamManager(data.os, data.name,
> > >>>> data.layout, true);
> > >>>>>>> +        }
> > >>>>>>> +    }
> > >>>>>>> +
> > >>>>>>> +    private static OutputStreamManagerFactory factory = new
> > >>>> OutputStreamManagerFactory();
> > >>>>>>> +
> > >>>>>>> +    /**
> > >>>>>>> +     * Creates an OutputStream Appender.
> > >>>>>>> +     *
> > >>>>>>> +     * @param layout
> > >>>>>>> +     *            The layout to use or null to get the default
> > >> layout.
> > >>>>>>> +     * @param filter
> > >>>>>>> +     *            The Filter or null.
> > >>>>>>> +     * @param target
> > >>>>>>> +     *            an output stream.
> > >>>>>>> +     * @param follow
> > >>>>>>> +     *            If true will follow changes to the underlying
> > >>>> output stream.
> > >>>>>>> +     *            Use false as the default.
> > >>>>>>> +     * @param name
> > >>>>>>> +     *            The name of the Appender (required).
> > >>>>>>> +     * @param ignore
> > >>>>>>> +     *            If {@code "true"} (default) exceptions
> > encountered
> > >>>> when
> > >>>>>>> +     *            appending events are logged; otherwise they
> are
> > >>>> propagated to
> > >>>>>>> +     *            the caller. Use true as the default.
> > >>>>>>> +     * @return The ConsoleAppender.
> > >>>>>>> +     */
> > >>>>>>> +    @PluginFactory
> > >>>>>>> +    public static OutputStreamAppender createAppender(Layout<?
> > >>>> extends Serializable> layout, final Filter filter,
> > >>>>>>> +            final OutputStream target, final String name, final
> > >>>> boolean follow, final boolean ignore) {
> > >>>>>>> +        if (name == null) {
> > >>>>>>> +            LOGGER.error("No name provided for
> > >> OutputStreamAppender");
> > >>>>>>> +            return null;
> > >>>>>>> +        }
> > >>>>>>> +        if (layout == null) {
> > >>>>>>> +            layout = PatternLayout.createDefaultLayout();
> > >>>>>>> +        }
> > >>>>>>> +        return new OutputStreamAppender(name, layout, filter,
> > >>>> getManager(target, follow, layout), ignore, null);
> > >>>>>>> +    }
> > >>>>>>> +
> > >>>>>>> +    private static OutputStreamManager getManager(final
> > OutputStream
> > >>>> target, final boolean follow,
> > >>>>>>> +            final Layout<? extends Serializable> layout) {
> > >>>>>>> +        final OutputStream os = target == null ?
> > >>>> NullOutputStream.getInstance() : new
> CloseShieldOutputStream(target);
> > >>>>>>> +        final OutputStream targetRef = target == null ? os :
> > target;
> > >>>>>>> +        final String managerName =
> targetRef.getClass().getName()
> > +
> > >>>> "@" + Integer.toHexString(targetRef.hashCode())
> > >>>>>>> +                + '.' + follow;
> > >>>>>>> +        return OutputStreamManager.getManager(managerName, new
> > >>>> FactoryData(os, managerName, layout), factory);
> > >>>>>>> +    }
> > >>>>>>> +
> > >>>>>>> +    @PluginBuilderFactory
> > >>>>>>> +    public static <B extends Builder<B>> B newBuilder() {
> > >>>>>>> +        return new Builder<B>().asBuilder();
> > >>>>>>> +    }
> > >>>>>>> +
> > >>>>>>> +    private OutputStreamAppender(final String name, final
> Layout<?
> > >>>> extends Serializable> layout, final Filter filter,
> > >>>>>>> +            final OutputStreamManager manager, final boolean
> > >>>> ignoreExceptions, final Property[] properties) {
> > >>>>>>> +        super(name, layout, filter, ignoreExceptions, true,
> > >>>> properties, manager);
> > >>>>>>> +    }
> > >>>>>>> +
> > >>>>>>> +}
> > >>>>>>> diff --git
> > >>>>
> > >>
> >
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> > >>>>
> > >>
> >
> b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> > >>>>>>> index 00af014..c1448bf 100644
> > >>>>>>> ---
> > >>>>
> > >>
> >
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> > >>>>>>> +++
> > >>>>
> > >>
> >
> b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> > >>>>>>> @@ -1,108 +1,122 @@
> > >>>>>>> -/*
> > >>>>>>> - * 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.
> > >>>>>>> - */
> > >>>>>>> -package org.apache.logging.log4j.core.appender;
> > >>>>>>> -
> > >>>>>>> -import java.io.BufferedOutputStream;
> > >>>>>>> -import java.io.ByteArrayOutputStream;
> > >>>>>>> -import java.io.OutputStream;
> > >>>>>>> -import java.sql.SQLException;
> > >>>>>>> -
> > >>>>>>> -import org.apache.logging.log4j.LogManager;
> > >>>>>>> -import org.apache.logging.log4j.Logger;
> > >>>>>>> -import org.apache.logging.log4j.core.Appender;
> > >>>>>>> -import org.apache.logging.log4j.core.LoggerContext;
> > >>>>>>> -import org.apache.logging.log4j.core.config.Configuration;
> > >>>>>>> -import org.apache.logging.log4j.core.layout.PatternLayout;
> > >>>>>>> -import org.junit.Assert;
> > >>>>>>> -import org.junit.Rule;
> > >>>>>>> -import org.junit.Test;
> > >>>>>>> -import org.junit.rules.TestName;
> > >>>>>>> -
> > >>>>>>> -/**
> > >>>>>>> - * Tests {@link OutputStreamAppender}.
> > >>>>>>> - */
> > >>>>>>> -public class OutputStreamAppenderTest {
> > >>>>>>> -
> > >>>>>>> -    private static final String TEST_MSG = "FOO ERROR";
> > >>>>>>> -
> > >>>>>>> -    @Rule
> > >>>>>>> -    public TestName testName = new TestName();
> > >>>>>>> -
> > >>>>>>> -    private String getName(final OutputStream out) {
> > >>>>>>> -        return out.getClass().getSimpleName() + "." +
> > >>>> testName.getMethodName();
> > >>>>>>> -    }
> > >>>>>>> -
> > >>>>>>> -    /**
> > >>>>>>> -     * Tests that you can add an output stream appender
> > dynamically.
> > >>>>>>> -     */
> > >>>>>>> -    private void addAppender(final OutputStream outputStream,
> > final
> > >>>> String outputStreamName) {
> > >>>>>>> -        final LoggerContext context =
> > >> LoggerContext.getContext(false);
> > >>>>>>> -        final Configuration config = context.getConfiguration();
> > >>>>>>> -        final PatternLayout layout =
> > >>>> PatternLayout.createDefaultLayout(config);
> > >>>>>>> -        final Appender appender =
> > >>>> OutputStreamAppender.createAppender(layout, null, outputStream,
> > >>>> outputStreamName, false, true);
> > >>>>>>> -        appender.start();
> > >>>>>>> -        config.addAppender(appender);
> > >>>>>>> -        ConfigurationTestUtils.updateLoggers(appender, config);
> > >>>>>>> -    }
> > >>>>>>> -
> > >>>>>>> -    @Test
> > >>>>>>> -    public void testOutputStreamAppenderToBufferedOutputStream()
> > >>>> throws SQLException {
> > >>>>>>> -        final ByteArrayOutputStream out = new
> > >> ByteArrayOutputStream();
> > >>>>>>> -        final OutputStream os = new BufferedOutputStream(out);
> > >>>>>>> -        final String name = getName(out);
> > >>>>>>> -        final Logger logger = LogManager.getLogger(name);
> > >>>>>>> -        addAppender(os, name);
> > >>>>>>> -        logger.error(TEST_MSG);
> > >>>>>>> -        final String actual = out.toString();
> > >>>>>>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> > >>>>>>> -    }
> > >>>>>>> -
> > >>>>>>> -    @Test
> > >>>>>>> -    public void
> testOutputStreamAppenderToByteArrayOutputStream()
> > >>>> throws SQLException {
> > >>>>>>> -        final OutputStream out = new ByteArrayOutputStream();
> > >>>>>>> -        final String name = getName(out);
> > >>>>>>> -        final Logger logger = LogManager.getLogger(name);
> > >>>>>>> -        addAppender(out, name);
> > >>>>>>> -        logger.error(TEST_MSG);
> > >>>>>>> -        final String actual = out.toString();
> > >>>>>>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> > >>>>>>> -    }
> > >>>>>>> -
> > >>>>>>> -    /**
> > >>>>>>> -     * Validates that the code pattern we use to add an appender
> > on
> > >>>> the fly
> > >>>>>>> -     * works with a basic appender that is not the new
> > OutputStream
> > >>>> appender or
> > >>>>>>> -     * new Writer appender.
> > >>>>>>> -     */
> > >>>>>>> -    @Test
> > >>>>>>> -    public void testUpdatePatternWithFileAppender() {
> > >>>>>>> -        final LoggerContext ctx = (LoggerContext)
> > >>>> LogManager.getContext(false);
> > >>>>>>> -        final Configuration config = ctx.getConfiguration();
> > >>>>>>> -        // @formatter:off
> > >>>>>>> -        final Appender appender = FileAppender.newBuilder()
> > >>>>>>> -        .withFileName("target/" + getClass().getName() + ".log")
> > >>>>>>> -
> > >> .withAppend(false).setName("File").setIgnoreExceptions(false)
> > >>>>>>> -            .withBufferedIo(false)
> > >>>>>>> -            .withBufferSize(4000)
> > >>>>>>> -            .setConfiguration(config)
> > >>>>>>> -            .build();
> > >>>>>>> -        // @formatter:on
> > >>>>>>> -        appender.start();
> > >>>>>>> -        config.addAppender(appender);
> > >>>>>>> -        ConfigurationTestUtils.updateLoggers(appender, config);
> > >>>>>>> -        LogManager.getLogger().error("FOO MSG");
> > >>>>>>> -    }
> > >>>>>>> -}
> > >>>>>>> +/*
> > >>>>>>> + * 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.
> > >>>>>>> + */
> > >>>>>>> +package org.apache.logging.log4j.core.appender;
> > >>>>>>> +
> > >>>>>>> +import java.io.BufferedOutputStream;
> > >>>>>>> +import java.io.ByteArrayOutputStream;
> > >>>>>>> +import java.io.OutputStream;
> > >>>>>>> +import java.sql.SQLException;
> > >>>>>>> +
> > >>>>>>> +import org.apache.logging.log4j.LogManager;
> > >>>>>>> +import org.apache.logging.log4j.Logger;
> > >>>>>>> +import org.apache.logging.log4j.core.Appender;
> > >>>>>>> +import org.apache.logging.log4j.core.LoggerContext;
> > >>>>>>> +import org.apache.logging.log4j.core.config.Configuration;
> > >>>>>>> +import org.apache.logging.log4j.core.filter.NoMarkerFilter;
> > >>>>>>> +import org.apache.logging.log4j.core.layout.PatternLayout;
> > >>>>>>> +import org.junit.Assert;
> > >>>>>>> +import org.junit.Rule;
> > >>>>>>> +import org.junit.Test;
> > >>>>>>> +import org.junit.rules.TestName;
> > >>>>>>> +
> > >>>>>>> +/**
> > >>>>>>> + * Tests {@link OutputStreamAppender}.
> > >>>>>>> + */
> > >>>>>>> +public class OutputStreamAppenderTest {
> > >>>>>>> +
> > >>>>>>> +    private static final String TEST_MSG = "FOO ERROR";
> > >>>>>>> +
> > >>>>>>> +    @Rule
> > >>>>>>> +    public TestName testName = new TestName();
> > >>>>>>> +
> > >>>>>>> +    private String getName(final OutputStream out) {
> > >>>>>>> +        return out.getClass().getSimpleName() + "." +
> > >>>> testName.getMethodName();
> > >>>>>>> +    }
> > >>>>>>> +
> > >>>>>>> +    /**
> > >>>>>>> +     * Tests that you can add an output stream appender
> > dynamically.
> > >>>>>>> +     */
> > >>>>>>> +    private void addAppender(final OutputStream outputStream,
> > final
> > >>>> String outputStreamName) {
> > >>>>>>> +        final LoggerContext context =
> > >> LoggerContext.getContext(false);
> > >>>>>>> +        final Configuration config = context.getConfiguration();
> > >>>>>>> +        final PatternLayout layout =
> > >>>> PatternLayout.createDefaultLayout(config);
> > >>>>>>> +        final Appender appender =
> > >>>> OutputStreamAppender.createAppender(layout, null, outputStream,
> > >>>> outputStreamName, false, true);
> > >>>>>>> +        appender.start();
> > >>>>>>> +        config.addAppender(appender);
> > >>>>>>> +        ConfigurationTestUtils.updateLoggers(appender, config);
> > >>>>>>> +    }
> > >>>>>>> +
> > >>>>>>> +    @Test
> > >>>>>>> +    public void testBuildFilter() {
> > >>>>>>> +        final NoMarkerFilter filter =
> > >>>> NoMarkerFilter.newBuilder().build();
> > >>>>>>> +        // @formatter:off
> > >>>>>>> +        final OutputStreamAppender.Builder builder =
> > >>>> OutputStreamAppender.newBuilder()
> > >>>>>>> +                .setName("test")
> > >>>>>>> +                .setFilter(filter);
> > >>>>>>> +        // @formatter:on
> > >>>>>>> +        Assert.assertEquals(filter, builder.getFilter());
> > >>>>>>> +        final OutputStreamAppender appender = builder.build();
> > >>>>>>> +        Assert.assertEquals(filter, appender.getFilter());
> > >>>>>>> +    }
> > >>>>>>> +
> > >>>>>>> +    @Test
> > >>>>>>> +    public void testOutputStreamAppenderToBufferedOutputStream()
> > >>>> throws SQLException {
> > >>>>>>> +        final ByteArrayOutputStream out = new
> > >> ByteArrayOutputStream();
> > >>>>>>> +        final OutputStream os = new BufferedOutputStream(out);
> > >>>>>>> +        final String name = getName(out);
> > >>>>>>> +        final Logger logger = LogManager.getLogger(name);
> > >>>>>>> +        addAppender(os, name);
> > >>>>>>> +        logger.error(TEST_MSG);
> > >>>>>>> +        final String actual = out.toString();
> > >>>>>>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> > >>>>>>> +    }
> > >>>>>>> +
> > >>>>>>> +    @Test
> > >>>>>>> +    public void
> testOutputStreamAppenderToByteArrayOutputStream()
> > >>>> throws SQLException {
> > >>>>>>> +        final OutputStream out = new ByteArrayOutputStream();
> > >>>>>>> +        final String name = getName(out);
> > >>>>>>> +        final Logger logger = LogManager.getLogger(name);
> > >>>>>>> +        addAppender(out, name);
> > >>>>>>> +        logger.error(TEST_MSG);
> > >>>>>>> +        final String actual = out.toString();
> > >>>>>>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> > >>>>>>> +    }
> > >>>>>>> +
> > >>>>>>> +    /**
> > >>>>>>> +     * Validates that the code pattern we use to add an appender
> > on
> > >>>> the fly
> > >>>>>>> +     * works with a basic appender that is not the new
> > OutputStream
> > >>>> appender or
> > >>>>>>> +     * new Writer appender.
> > >>>>>>> +     */
> > >>>>>>> +    @Test
> > >>>>>>> +    public void testUpdatePatternWithFileAppender() {
> > >>>>>>> +        final LoggerContext ctx = (LoggerContext)
> > >>>> LogManager.getContext(false);
> > >>>>>>> +        final Configuration config = ctx.getConfiguration();
> > >>>>>>> +        // @formatter:off
> > >>>>>>> +        final Appender appender = FileAppender.newBuilder()
> > >>>>>>> +        .withFileName("target/" + getClass().getName() + ".log")
> > >>>>>>> +
> > >> .withAppend(false).setName("File").setIgnoreExceptions(false)
> > >>>>>>> +            .withBufferedIo(false)
> > >>>>>>> +            .withBufferSize(4000)
> > >>>>>>> +            .setConfiguration(config)
> > >>>>>>> +            .build();
> > >>>>>>> +        // @formatter:on
> > >>>>>>> +        appender.start();
> > >>>>>>> +        config.addAppender(appender);
> > >>>>>>> +        ConfigurationTestUtils.updateLoggers(appender, config);
> > >>>>>>> +        LogManager.getLogger().error("FOO MSG");
> > >>>>>>> +    }
> > >>>>>>> +}
> > >>>>>>> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
> > >>>>>>> index c3483bd..a9ec160 100644
> > >>>>>>> --- a/src/changes/changes.xml
> > >>>>>>> +++ b/src/changes/changes.xml
> > >>>>>>> @@ -33,6 +33,9 @@
> > >>>>>>>   <action issue="LOG4J2-2639" dev="rgoers" type="add">
> > >>>>>>>     Add builder pattern to Logger interface.
> > >>>>>>>   </action>
> > >>>>>>> +      <action issue="LOG4J2-2673" dev="ggregory" type="fix"
> > >>>> due-to="Yuichi Sugimura, Gary Gregory">
> > >>>>>>> +        OutputStreamAppender.Builder ignores setFilter().
> > >>>>>>> +      </action>
> > >>>>>>> </release>
> > >>>>>>> <release version="2.12.1" date="2019-08-06" description="GA
> Release
> > >>>> 2.12.1">
> > >>>>>>>   <action issue="LOG4J2-1946" dev="rgoers" type="fix"
> due-to="Igor
> > >>>> Perelyotov">
> > >>>>>>>
> > >>>>>>>
> > >>>>>>
> > >>>>>>
> > >>>>>>
> > >>>>>
> > >>>>>
> > >>>>>
> > >>>>
> > >>>>
> > >>>>
> > >>
> > >>
> > >>
> >
> >
> >
>
-- 
Matt Sicker <bo...@gmail.com>

Re: [logging-log4j2] branch release-2.x updated: [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().

Posted by Gary Gregory <ga...@gmail.com>.
Check. I updated the RevApi config.

Gary

On Fri, Aug 16, 2019 at 1:30 PM Ralph Goers <ra...@dslextreme.com>
wrote:

> You may not be missing anything. If you don’t think it is a problem then
> just add the config items revapi spits out to the configuration. There are
> some there already so you can look at the justifications for those as
> examples.
>
> Ralph
>
> > On Aug 16, 2019, at 11:23 AM, Gary Gregory <ga...@gmail.com>
> wrote:
> >
> > It looks like a bug in revapi to me: it does not know about type
> erasures.
> > I created a new Maven project that depends on Log4j Core 2.12.1 with:
> >
> > public class App
> > {
> >    public static void main( String[] args )
> >    {
> >        System.out.println( "Hello World!" );
> >        Builder builder = OutputStreamAppender.newBuilder();
> >    }
> > }
> >
> > Then I ran that class against 2.13.-SNAPSHOT Core without recompiling and
> > it ran fine.
> >
> > What am I missing?
> >
> > Gary
> >
> > On Thu, Aug 15, 2019 at 5:03 PM Ralph Goers <ra...@dslextreme.com>
> > wrote:
> >
> >> I believe you have not read this thread. I am not talking about the bug
> >> you fixed. I am talking the compatibility breakage you created.
> >>
> >> 1. The backward compatibility breakage only occurred on the release-2.x
> >> branch because revapi is essentially disabled on master. Too much has
> >> changed to bother keeping track.
> >> 2. I haven’t seen any commit messages indicating you committed anything
> to
> >> fix this.
> >> 3. The build is still failing for me.  Try running mvn clean install
> >> -DskipTests in log4j-core. It will break for you too.
> >>
> >> Please look at the Jenkins build and fix the problems by either
> reverting
> >> the breakage or by adding the recommended changes to revapi.json to
> >> document why compatibility was broken.
> >>
> >> Ralph
> >>
> >>
> >>> On Aug 15, 2019, at 4:54 PM, Gary Gregory <ga...@gmail.com>
> >> wrote:
> >>>
> >>> I fixed it already in both branches.
> >>>
> >>> Gary
> >>>
> >>> On Thu, Aug 15, 2019, 10:42 Ralph Goers <ra...@dslextreme.com>
> >> wrote:
> >>>
> >>>> Gary,
> >>>>
> >>>> Are you going to look into this?
> >>>>
> >>>> Ralph
> >>>>
> >>>>> On Aug 14, 2019, at 9:17 AM, Ralph Goers <ralph.goers@dslextreme.com
> >
> >>>> wrote:
> >>>>>
> >>>>> Any update on this? I’d like my builds to work again.
> >>>>>
> >>>>> Ralph
> >>>>>
> >>>>>> On Aug 13, 2019, at 4:29 PM, Ralph Goers <
> ralph.goers@dslextreme.com>
> >>>> wrote:
> >>>>>>
> >>>>>> Gary,
> >>>>>>
> >>>>>> It seems this change broker compatibility. Please see the Jenkins
> >>>> failure. You either need to resolve the code so compatibility is
> >> maintained
> >>>> or update revapi.json with the recommended changes.
> >>>>>>
> >>>>>> Ralph
> >>>>>>
> >>>>>>> On Aug 13, 2019, at 2:06 PM, ggregory@apache.org wrote:
> >>>>>>>
> >>>>>>> This is an automated email from the ASF dual-hosted git repository.
> >>>>>>>
> >>>>>>> ggregory pushed a commit to branch release-2.x
> >>>>>>> in repository
> https://gitbox.apache.org/repos/asf/logging-log4j2.git
> >>>>>>>
> >>>>>>>
> >>>>>>> The following commit(s) were added to refs/heads/release-2.x by
> this
> >>>> push:
> >>>>>>> new 4679a08  [LOG4J2-2673] OutputStreamAppender.Builder ignores
> >>>> setFilter().
> >>>>>>> 4679a08 is described below
> >>>>>>>
> >>>>>>> commit 4679a08d4899350f7ee19d050d2a96783b748066
> >>>>>>> Author: Gary Gregory <ga...@gmail.com>
> >>>>>>> AuthorDate: Tue Aug 13 17:06:48 2019 -0400
> >>>>>>>
> >>>>>>> [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
> >>>>>>>
> >>>>>>> Also allow a null output stream for convenience instead of an NPE.
> >>>>>>> ---
> >>>>>>> .../log4j/core/appender/OutputStreamAppender.java  | 351
> >>>> +++++++++++----------
> >>>>>>> .../core/appender/OutputStreamAppenderTest.java    | 230
> >> +++++++-------
> >>>>>>> src/changes/changes.xml                            |   3 +
> >>>>>>> 3 files changed, 302 insertions(+), 282 deletions(-)
> >>>>>>>
> >>>>>>> diff --git
> >>>>
> >>
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>>>
> >>
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>>>>>> index 7dfd187..dc6f352 100644
> >>>>>>> ---
> >>>>
> >>
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>>>>>> +++
> >>>>
> >>
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>>>>>> @@ -1,174 +1,177 @@
> >>>>>>> -/*
> >>>>>>> - * 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.
> >>>>>>> - */
> >>>>>>> -package org.apache.logging.log4j.core.appender;
> >>>>>>> -
> >>>>>>> -import java.io.OutputStream;
> >>>>>>> -import java.io.Serializable;
> >>>>>>> -
> >>>>>>> -import org.apache.logging.log4j.core.Appender;
> >>>>>>> -import org.apache.logging.log4j.core.Core;
> >>>>>>> -import org.apache.logging.log4j.core.Filter;
> >>>>>>> -import org.apache.logging.log4j.core.Layout;
> >>>>>>> -import org.apache.logging.log4j.core.config.Property;
> >>>>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> >>>>>>> -import
> >>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
> >>>>>>> -import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> >>>>>>> -import org.apache.logging.log4j.core.layout.PatternLayout;
> >>>>>>> -import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
> >>>>>>> -
> >>>>>>> -/**
> >>>>>>> - * Appends log events to a given output stream using a layout.
> >>>>>>> - * <p>
> >>>>>>> - * Character encoding is handled within the Layout.
> >>>>>>> - * </p>
> >>>>>>> - */
> >>>>>>> -@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME,
> >>>> elementType = Appender.ELEMENT_TYPE, printObject = true)
> >>>>>>> -public final class OutputStreamAppender extends
> >>>> AbstractOutputStreamAppender<OutputStreamManager> {
> >>>>>>> -
> >>>>>>> -    /**
> >>>>>>> -     * Builds OutputStreamAppender instances.
> >>>>>>> -     */
> >>>>>>> -    public static class Builder<B extends Builder<B>> extends
> >>>> AbstractOutputStreamAppender.Builder<B>
> >>>>>>> -            implements
> >>>> org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
> >>>>>>> -
> >>>>>>> -        private Filter filter;
> >>>>>>> -
> >>>>>>> -        private boolean follow = false;
> >>>>>>> -
> >>>>>>> -        private final boolean ignoreExceptions = true;
> >>>>>>> -
> >>>>>>> -        private OutputStream target;
> >>>>>>> -
> >>>>>>> -        @Override
> >>>>>>> -        public OutputStreamAppender build() {
> >>>>>>> -            final Layout<? extends Serializable> layout =
> >> getLayout();
> >>>>>>> -            final Layout<? extends Serializable> actualLayout =
> >>>> layout == null ? PatternLayout.createDefaultLayout()
> >>>>>>> -                    : layout;
> >>>>>>> -            return new OutputStreamAppender(getName(),
> actualLayout,
> >>>> filter, getManager(target, follow, actualLayout),
> >>>>>>> -                    ignoreExceptions, getPropertyArray());
> >>>>>>> -        }
> >>>>>>> -
> >>>>>>> -        public B setFollow(final boolean shouldFollow) {
> >>>>>>> -            this.follow = shouldFollow;
> >>>>>>> -            return asBuilder();
> >>>>>>> -        }
> >>>>>>> -
> >>>>>>> -        public B setTarget(final OutputStream aTarget) {
> >>>>>>> -            this.target = aTarget;
> >>>>>>> -            return asBuilder();
> >>>>>>> -        }
> >>>>>>> -    }
> >>>>>>> -
> >>>>>>> -    /**
> >>>>>>> -     * Holds data to pass to factory method.
> >>>>>>> -     */
> >>>>>>> -    private static class FactoryData {
> >>>>>>> -        private final Layout<? extends Serializable> layout;
> >>>>>>> -        private final String name;
> >>>>>>> -        private final OutputStream os;
> >>>>>>> -
> >>>>>>> -        /**
> >>>>>>> -         * Builds instances.
> >>>>>>> -         *
> >>>>>>> -         * @param os
> >>>>>>> -         *            The OutputStream.
> >>>>>>> -         * @param type
> >>>>>>> -         *            The name of the target.
> >>>>>>> -         * @param layout
> >>>>>>> -         *            A Serializable layout
> >>>>>>> -         */
> >>>>>>> -        public FactoryData(final OutputStream os, final String
> type,
> >>>> final Layout<? extends Serializable> layout) {
> >>>>>>> -            this.os = os;
> >>>>>>> -            this.name = type;
> >>>>>>> -            this.layout = layout;
> >>>>>>> -        }
> >>>>>>> -    }
> >>>>>>> -
> >>>>>>> -    /**
> >>>>>>> -     * Creates the manager.
> >>>>>>> -     */
> >>>>>>> -    private static class OutputStreamManagerFactory implements
> >>>> ManagerFactory<OutputStreamManager, FactoryData> {
> >>>>>>> -
> >>>>>>> -        /**
> >>>>>>> -         * Creates an OutputStreamManager.
> >>>>>>> -         *
> >>>>>>> -         * @param name
> >>>>>>> -         *            The name of the entity to manage.
> >>>>>>> -         * @param data
> >>>>>>> -         *            The data required to create the entity.
> >>>>>>> -         * @return The OutputStreamManager
> >>>>>>> -         */
> >>>>>>> -        @Override
> >>>>>>> -        public OutputStreamManager createManager(final String
> name,
> >>>> final FactoryData data) {
> >>>>>>> -            return new OutputStreamManager(data.os, data.name,
> >>>> data.layout, true);
> >>>>>>> -        }
> >>>>>>> -    }
> >>>>>>> -
> >>>>>>> -    private static OutputStreamManagerFactory factory = new
> >>>> OutputStreamManagerFactory();
> >>>>>>> -
> >>>>>>> -    /**
> >>>>>>> -     * Creates an OutputStream Appender.
> >>>>>>> -     *
> >>>>>>> -     * @param layout
> >>>>>>> -     *            The layout to use or null to get the default
> >> layout.
> >>>>>>> -     * @param filter
> >>>>>>> -     *            The Filter or null.
> >>>>>>> -     * @param target
> >>>>>>> -     *            an output stream.
> >>>>>>> -     * @param follow
> >>>>>>> -     *            If true will follow changes to the underlying
> >>>> output stream.
> >>>>>>> -     *            Use false as the default.
> >>>>>>> -     * @param name
> >>>>>>> -     *            The name of the Appender (required).
> >>>>>>> -     * @param ignore
> >>>>>>> -     *            If {@code "true"} (default) exceptions
> encountered
> >>>> when
> >>>>>>> -     *            appending events are logged; otherwise they are
> >>>> propagated to
> >>>>>>> -     *            the caller. Use true as the default.
> >>>>>>> -     * @return The ConsoleAppender.
> >>>>>>> -     */
> >>>>>>> -    @PluginFactory
> >>>>>>> -    public static OutputStreamAppender createAppender(Layout<?
> >>>> extends Serializable> layout, final Filter filter,
> >>>>>>> -            final OutputStream target, final String name, final
> >>>> boolean follow, final boolean ignore) {
> >>>>>>> -        if (name == null) {
> >>>>>>> -            LOGGER.error("No name provided for
> >> OutputStreamAppender");
> >>>>>>> -            return null;
> >>>>>>> -        }
> >>>>>>> -        if (layout == null) {
> >>>>>>> -            layout = PatternLayout.createDefaultLayout();
> >>>>>>> -        }
> >>>>>>> -        return new OutputStreamAppender(name, layout, filter,
> >>>> getManager(target, follow, layout), ignore, null);
> >>>>>>> -    }
> >>>>>>> -
> >>>>>>> -    private static OutputStreamManager getManager(final
> OutputStream
> >>>> target, final boolean follow,
> >>>>>>> -            final Layout<? extends Serializable> layout) {
> >>>>>>> -        final OutputStream os = new
> CloseShieldOutputStream(target);
> >>>>>>> -        final String managerName = target.getClass().getName() +
> "@"
> >>>> + Integer.toHexString(target.hashCode()) + '.'
> >>>>>>> -                + follow;
> >>>>>>> -        return OutputStreamManager.getManager(managerName, new
> >>>> FactoryData(os, managerName, layout), factory);
> >>>>>>> -    }
> >>>>>>> -
> >>>>>>> -    @PluginBuilderFactory
> >>>>>>> -    public static Builder newBuilder() {
> >>>>>>> -        return new Builder();
> >>>>>>> -    }
> >>>>>>> -
> >>>>>>> -    private OutputStreamAppender(final String name, final Layout<?
> >>>> extends Serializable> layout, final Filter filter,
> >>>>>>> -            final OutputStreamManager manager, final boolean
> >>>> ignoreExceptions, final Property[] properties) {
> >>>>>>> -        super(name, layout, filter, ignoreExceptions, true,
> >>>> properties, manager);
> >>>>>>> -    }
> >>>>>>> -
> >>>>>>> -}
> >>>>>>> +/*
> >>>>>>> + * 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.
> >>>>>>> + */
> >>>>>>> +package org.apache.logging.log4j.core.appender;
> >>>>>>> +
> >>>>>>> +import java.io.OutputStream;
> >>>>>>> +import java.io.Serializable;
> >>>>>>> +
> >>>>>>> +import org.apache.logging.log4j.core.Appender;
> >>>>>>> +import org.apache.logging.log4j.core.Core;
> >>>>>>> +import org.apache.logging.log4j.core.Filter;
> >>>>>>> +import org.apache.logging.log4j.core.Layout;
> >>>>>>> +import org.apache.logging.log4j.core.config.Property;
> >>>>>>> +import org.apache.logging.log4j.core.config.plugins.Plugin;
> >>>>>>> +import
> >>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
> >>>>>>> +import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> >>>>>>> +import org.apache.logging.log4j.core.layout.PatternLayout;
> >>>>>>> +import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
> >>>>>>> +import org.apache.logging.log4j.core.util.NullOutputStream;
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Appends log events to a given output stream using a layout.
> >>>>>>> + * <p>
> >>>>>>> + * Character encoding is handled within the Layout.
> >>>>>>> + * </p>
> >>>>>>> + */
> >>>>>>> +@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME,
> >>>> elementType = Appender.ELEMENT_TYPE, printObject = true)
> >>>>>>> +public final class OutputStreamAppender extends
> >>>> AbstractOutputStreamAppender<OutputStreamManager> {
> >>>>>>> +
> >>>>>>> +    /**
> >>>>>>> +     * Builds OutputStreamAppender instances.
> >>>>>>> +     *
> >>>>>>> +     * @param <B>
> >>>>>>> +     *            The type to build.
> >>>>>>> +     */
> >>>>>>> +    public static class Builder<B extends Builder<B>> extends
> >>>> AbstractOutputStreamAppender.Builder<B>
> >>>>>>> +            implements
> >>>> org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
> >>>>>>> +
> >>>>>>> +        private boolean follow = false;
> >>>>>>> +
> >>>>>>> +        private final boolean ignoreExceptions = true;
> >>>>>>> +
> >>>>>>> +        private OutputStream target;
> >>>>>>> +
> >>>>>>> +        @Override
> >>>>>>> +        public OutputStreamAppender build() {
> >>>>>>> +            final Layout<? extends Serializable> layout =
> >> getLayout();
> >>>>>>> +            final Layout<? extends Serializable> actualLayout =
> >>>> layout == null ? PatternLayout.createDefaultLayout()
> >>>>>>> +                    : layout;
> >>>>>>> +            return new OutputStreamAppender(getName(),
> actualLayout,
> >>>> getFilter(), getManager(target, follow, actualLayout),
> >>>>>>> +                    ignoreExceptions, getPropertyArray());
> >>>>>>> +        }
> >>>>>>> +
> >>>>>>> +        public B setFollow(final boolean shouldFollow) {
> >>>>>>> +            this.follow = shouldFollow;
> >>>>>>> +            return asBuilder();
> >>>>>>> +        }
> >>>>>>> +
> >>>>>>> +        public B setTarget(final OutputStream aTarget) {
> >>>>>>> +            this.target = aTarget;
> >>>>>>> +            return asBuilder();
> >>>>>>> +        }
> >>>>>>> +    }
> >>>>>>> +
> >>>>>>> +    /**
> >>>>>>> +     * Holds data to pass to factory method.
> >>>>>>> +     */
> >>>>>>> +    private static class FactoryData {
> >>>>>>> +        private final Layout<? extends Serializable> layout;
> >>>>>>> +        private final String name;
> >>>>>>> +        private final OutputStream os;
> >>>>>>> +
> >>>>>>> +        /**
> >>>>>>> +         * Builds instances.
> >>>>>>> +         *
> >>>>>>> +         * @param os
> >>>>>>> +         *            The OutputStream.
> >>>>>>> +         * @param type
> >>>>>>> +         *            The name of the target.
> >>>>>>> +         * @param layout
> >>>>>>> +         *            A Serializable layout
> >>>>>>> +         */
> >>>>>>> +        public FactoryData(final OutputStream os, final String
> type,
> >>>> final Layout<? extends Serializable> layout) {
> >>>>>>> +            this.os = os;
> >>>>>>> +            this.name = type;
> >>>>>>> +            this.layout = layout;
> >>>>>>> +        }
> >>>>>>> +    }
> >>>>>>> +
> >>>>>>> +    /**
> >>>>>>> +     * Creates the manager.
> >>>>>>> +     */
> >>>>>>> +    private static class OutputStreamManagerFactory implements
> >>>> ManagerFactory<OutputStreamManager, FactoryData> {
> >>>>>>> +
> >>>>>>> +        /**
> >>>>>>> +         * Creates an OutputStreamManager.
> >>>>>>> +         *
> >>>>>>> +         * @param name
> >>>>>>> +         *            The name of the entity to manage.
> >>>>>>> +         * @param data
> >>>>>>> +         *            The data required to create the entity.
> >>>>>>> +         * @return The OutputStreamManager
> >>>>>>> +         */
> >>>>>>> +        @Override
> >>>>>>> +        public OutputStreamManager createManager(final String
> name,
> >>>> final FactoryData data) {
> >>>>>>> +            return new OutputStreamManager(data.os, data.name,
> >>>> data.layout, true);
> >>>>>>> +        }
> >>>>>>> +    }
> >>>>>>> +
> >>>>>>> +    private static OutputStreamManagerFactory factory = new
> >>>> OutputStreamManagerFactory();
> >>>>>>> +
> >>>>>>> +    /**
> >>>>>>> +     * Creates an OutputStream Appender.
> >>>>>>> +     *
> >>>>>>> +     * @param layout
> >>>>>>> +     *            The layout to use or null to get the default
> >> layout.
> >>>>>>> +     * @param filter
> >>>>>>> +     *            The Filter or null.
> >>>>>>> +     * @param target
> >>>>>>> +     *            an output stream.
> >>>>>>> +     * @param follow
> >>>>>>> +     *            If true will follow changes to the underlying
> >>>> output stream.
> >>>>>>> +     *            Use false as the default.
> >>>>>>> +     * @param name
> >>>>>>> +     *            The name of the Appender (required).
> >>>>>>> +     * @param ignore
> >>>>>>> +     *            If {@code "true"} (default) exceptions
> encountered
> >>>> when
> >>>>>>> +     *            appending events are logged; otherwise they are
> >>>> propagated to
> >>>>>>> +     *            the caller. Use true as the default.
> >>>>>>> +     * @return The ConsoleAppender.
> >>>>>>> +     */
> >>>>>>> +    @PluginFactory
> >>>>>>> +    public static OutputStreamAppender createAppender(Layout<?
> >>>> extends Serializable> layout, final Filter filter,
> >>>>>>> +            final OutputStream target, final String name, final
> >>>> boolean follow, final boolean ignore) {
> >>>>>>> +        if (name == null) {
> >>>>>>> +            LOGGER.error("No name provided for
> >> OutputStreamAppender");
> >>>>>>> +            return null;
> >>>>>>> +        }
> >>>>>>> +        if (layout == null) {
> >>>>>>> +            layout = PatternLayout.createDefaultLayout();
> >>>>>>> +        }
> >>>>>>> +        return new OutputStreamAppender(name, layout, filter,
> >>>> getManager(target, follow, layout), ignore, null);
> >>>>>>> +    }
> >>>>>>> +
> >>>>>>> +    private static OutputStreamManager getManager(final
> OutputStream
> >>>> target, final boolean follow,
> >>>>>>> +            final Layout<? extends Serializable> layout) {
> >>>>>>> +        final OutputStream os = target == null ?
> >>>> NullOutputStream.getInstance() : new CloseShieldOutputStream(target);
> >>>>>>> +        final OutputStream targetRef = target == null ? os :
> target;
> >>>>>>> +        final String managerName = targetRef.getClass().getName()
> +
> >>>> "@" + Integer.toHexString(targetRef.hashCode())
> >>>>>>> +                + '.' + follow;
> >>>>>>> +        return OutputStreamManager.getManager(managerName, new
> >>>> FactoryData(os, managerName, layout), factory);
> >>>>>>> +    }
> >>>>>>> +
> >>>>>>> +    @PluginBuilderFactory
> >>>>>>> +    public static <B extends Builder<B>> B newBuilder() {
> >>>>>>> +        return new Builder<B>().asBuilder();
> >>>>>>> +    }
> >>>>>>> +
> >>>>>>> +    private OutputStreamAppender(final String name, final Layout<?
> >>>> extends Serializable> layout, final Filter filter,
> >>>>>>> +            final OutputStreamManager manager, final boolean
> >>>> ignoreExceptions, final Property[] properties) {
> >>>>>>> +        super(name, layout, filter, ignoreExceptions, true,
> >>>> properties, manager);
> >>>>>>> +    }
> >>>>>>> +
> >>>>>>> +}
> >>>>>>> diff --git
> >>>>
> >>
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>>>
> >>
> b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>>>>>> index 00af014..c1448bf 100644
> >>>>>>> ---
> >>>>
> >>
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>>>>>> +++
> >>>>
> >>
> b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>>>>>> @@ -1,108 +1,122 @@
> >>>>>>> -/*
> >>>>>>> - * 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.
> >>>>>>> - */
> >>>>>>> -package org.apache.logging.log4j.core.appender;
> >>>>>>> -
> >>>>>>> -import java.io.BufferedOutputStream;
> >>>>>>> -import java.io.ByteArrayOutputStream;
> >>>>>>> -import java.io.OutputStream;
> >>>>>>> -import java.sql.SQLException;
> >>>>>>> -
> >>>>>>> -import org.apache.logging.log4j.LogManager;
> >>>>>>> -import org.apache.logging.log4j.Logger;
> >>>>>>> -import org.apache.logging.log4j.core.Appender;
> >>>>>>> -import org.apache.logging.log4j.core.LoggerContext;
> >>>>>>> -import org.apache.logging.log4j.core.config.Configuration;
> >>>>>>> -import org.apache.logging.log4j.core.layout.PatternLayout;
> >>>>>>> -import org.junit.Assert;
> >>>>>>> -import org.junit.Rule;
> >>>>>>> -import org.junit.Test;
> >>>>>>> -import org.junit.rules.TestName;
> >>>>>>> -
> >>>>>>> -/**
> >>>>>>> - * Tests {@link OutputStreamAppender}.
> >>>>>>> - */
> >>>>>>> -public class OutputStreamAppenderTest {
> >>>>>>> -
> >>>>>>> -    private static final String TEST_MSG = "FOO ERROR";
> >>>>>>> -
> >>>>>>> -    @Rule
> >>>>>>> -    public TestName testName = new TestName();
> >>>>>>> -
> >>>>>>> -    private String getName(final OutputStream out) {
> >>>>>>> -        return out.getClass().getSimpleName() + "." +
> >>>> testName.getMethodName();
> >>>>>>> -    }
> >>>>>>> -
> >>>>>>> -    /**
> >>>>>>> -     * Tests that you can add an output stream appender
> dynamically.
> >>>>>>> -     */
> >>>>>>> -    private void addAppender(final OutputStream outputStream,
> final
> >>>> String outputStreamName) {
> >>>>>>> -        final LoggerContext context =
> >> LoggerContext.getContext(false);
> >>>>>>> -        final Configuration config = context.getConfiguration();
> >>>>>>> -        final PatternLayout layout =
> >>>> PatternLayout.createDefaultLayout(config);
> >>>>>>> -        final Appender appender =
> >>>> OutputStreamAppender.createAppender(layout, null, outputStream,
> >>>> outputStreamName, false, true);
> >>>>>>> -        appender.start();
> >>>>>>> -        config.addAppender(appender);
> >>>>>>> -        ConfigurationTestUtils.updateLoggers(appender, config);
> >>>>>>> -    }
> >>>>>>> -
> >>>>>>> -    @Test
> >>>>>>> -    public void testOutputStreamAppenderToBufferedOutputStream()
> >>>> throws SQLException {
> >>>>>>> -        final ByteArrayOutputStream out = new
> >> ByteArrayOutputStream();
> >>>>>>> -        final OutputStream os = new BufferedOutputStream(out);
> >>>>>>> -        final String name = getName(out);
> >>>>>>> -        final Logger logger = LogManager.getLogger(name);
> >>>>>>> -        addAppender(os, name);
> >>>>>>> -        logger.error(TEST_MSG);
> >>>>>>> -        final String actual = out.toString();
> >>>>>>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>>>>>> -    }
> >>>>>>> -
> >>>>>>> -    @Test
> >>>>>>> -    public void testOutputStreamAppenderToByteArrayOutputStream()
> >>>> throws SQLException {
> >>>>>>> -        final OutputStream out = new ByteArrayOutputStream();
> >>>>>>> -        final String name = getName(out);
> >>>>>>> -        final Logger logger = LogManager.getLogger(name);
> >>>>>>> -        addAppender(out, name);
> >>>>>>> -        logger.error(TEST_MSG);
> >>>>>>> -        final String actual = out.toString();
> >>>>>>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>>>>>> -    }
> >>>>>>> -
> >>>>>>> -    /**
> >>>>>>> -     * Validates that the code pattern we use to add an appender
> on
> >>>> the fly
> >>>>>>> -     * works with a basic appender that is not the new
> OutputStream
> >>>> appender or
> >>>>>>> -     * new Writer appender.
> >>>>>>> -     */
> >>>>>>> -    @Test
> >>>>>>> -    public void testUpdatePatternWithFileAppender() {
> >>>>>>> -        final LoggerContext ctx = (LoggerContext)
> >>>> LogManager.getContext(false);
> >>>>>>> -        final Configuration config = ctx.getConfiguration();
> >>>>>>> -        // @formatter:off
> >>>>>>> -        final Appender appender = FileAppender.newBuilder()
> >>>>>>> -        .withFileName("target/" + getClass().getName() + ".log")
> >>>>>>> -
> >> .withAppend(false).setName("File").setIgnoreExceptions(false)
> >>>>>>> -            .withBufferedIo(false)
> >>>>>>> -            .withBufferSize(4000)
> >>>>>>> -            .setConfiguration(config)
> >>>>>>> -            .build();
> >>>>>>> -        // @formatter:on
> >>>>>>> -        appender.start();
> >>>>>>> -        config.addAppender(appender);
> >>>>>>> -        ConfigurationTestUtils.updateLoggers(appender, config);
> >>>>>>> -        LogManager.getLogger().error("FOO MSG");
> >>>>>>> -    }
> >>>>>>> -}
> >>>>>>> +/*
> >>>>>>> + * 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.
> >>>>>>> + */
> >>>>>>> +package org.apache.logging.log4j.core.appender;
> >>>>>>> +
> >>>>>>> +import java.io.BufferedOutputStream;
> >>>>>>> +import java.io.ByteArrayOutputStream;
> >>>>>>> +import java.io.OutputStream;
> >>>>>>> +import java.sql.SQLException;
> >>>>>>> +
> >>>>>>> +import org.apache.logging.log4j.LogManager;
> >>>>>>> +import org.apache.logging.log4j.Logger;
> >>>>>>> +import org.apache.logging.log4j.core.Appender;
> >>>>>>> +import org.apache.logging.log4j.core.LoggerContext;
> >>>>>>> +import org.apache.logging.log4j.core.config.Configuration;
> >>>>>>> +import org.apache.logging.log4j.core.filter.NoMarkerFilter;
> >>>>>>> +import org.apache.logging.log4j.core.layout.PatternLayout;
> >>>>>>> +import org.junit.Assert;
> >>>>>>> +import org.junit.Rule;
> >>>>>>> +import org.junit.Test;
> >>>>>>> +import org.junit.rules.TestName;
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + * Tests {@link OutputStreamAppender}.
> >>>>>>> + */
> >>>>>>> +public class OutputStreamAppenderTest {
> >>>>>>> +
> >>>>>>> +    private static final String TEST_MSG = "FOO ERROR";
> >>>>>>> +
> >>>>>>> +    @Rule
> >>>>>>> +    public TestName testName = new TestName();
> >>>>>>> +
> >>>>>>> +    private String getName(final OutputStream out) {
> >>>>>>> +        return out.getClass().getSimpleName() + "." +
> >>>> testName.getMethodName();
> >>>>>>> +    }
> >>>>>>> +
> >>>>>>> +    /**
> >>>>>>> +     * Tests that you can add an output stream appender
> dynamically.
> >>>>>>> +     */
> >>>>>>> +    private void addAppender(final OutputStream outputStream,
> final
> >>>> String outputStreamName) {
> >>>>>>> +        final LoggerContext context =
> >> LoggerContext.getContext(false);
> >>>>>>> +        final Configuration config = context.getConfiguration();
> >>>>>>> +        final PatternLayout layout =
> >>>> PatternLayout.createDefaultLayout(config);
> >>>>>>> +        final Appender appender =
> >>>> OutputStreamAppender.createAppender(layout, null, outputStream,
> >>>> outputStreamName, false, true);
> >>>>>>> +        appender.start();
> >>>>>>> +        config.addAppender(appender);
> >>>>>>> +        ConfigurationTestUtils.updateLoggers(appender, config);
> >>>>>>> +    }
> >>>>>>> +
> >>>>>>> +    @Test
> >>>>>>> +    public void testBuildFilter() {
> >>>>>>> +        final NoMarkerFilter filter =
> >>>> NoMarkerFilter.newBuilder().build();
> >>>>>>> +        // @formatter:off
> >>>>>>> +        final OutputStreamAppender.Builder builder =
> >>>> OutputStreamAppender.newBuilder()
> >>>>>>> +                .setName("test")
> >>>>>>> +                .setFilter(filter);
> >>>>>>> +        // @formatter:on
> >>>>>>> +        Assert.assertEquals(filter, builder.getFilter());
> >>>>>>> +        final OutputStreamAppender appender = builder.build();
> >>>>>>> +        Assert.assertEquals(filter, appender.getFilter());
> >>>>>>> +    }
> >>>>>>> +
> >>>>>>> +    @Test
> >>>>>>> +    public void testOutputStreamAppenderToBufferedOutputStream()
> >>>> throws SQLException {
> >>>>>>> +        final ByteArrayOutputStream out = new
> >> ByteArrayOutputStream();
> >>>>>>> +        final OutputStream os = new BufferedOutputStream(out);
> >>>>>>> +        final String name = getName(out);
> >>>>>>> +        final Logger logger = LogManager.getLogger(name);
> >>>>>>> +        addAppender(os, name);
> >>>>>>> +        logger.error(TEST_MSG);
> >>>>>>> +        final String actual = out.toString();
> >>>>>>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>>>>>> +    }
> >>>>>>> +
> >>>>>>> +    @Test
> >>>>>>> +    public void testOutputStreamAppenderToByteArrayOutputStream()
> >>>> throws SQLException {
> >>>>>>> +        final OutputStream out = new ByteArrayOutputStream();
> >>>>>>> +        final String name = getName(out);
> >>>>>>> +        final Logger logger = LogManager.getLogger(name);
> >>>>>>> +        addAppender(out, name);
> >>>>>>> +        logger.error(TEST_MSG);
> >>>>>>> +        final String actual = out.toString();
> >>>>>>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>>>>>> +    }
> >>>>>>> +
> >>>>>>> +    /**
> >>>>>>> +     * Validates that the code pattern we use to add an appender
> on
> >>>> the fly
> >>>>>>> +     * works with a basic appender that is not the new
> OutputStream
> >>>> appender or
> >>>>>>> +     * new Writer appender.
> >>>>>>> +     */
> >>>>>>> +    @Test
> >>>>>>> +    public void testUpdatePatternWithFileAppender() {
> >>>>>>> +        final LoggerContext ctx = (LoggerContext)
> >>>> LogManager.getContext(false);
> >>>>>>> +        final Configuration config = ctx.getConfiguration();
> >>>>>>> +        // @formatter:off
> >>>>>>> +        final Appender appender = FileAppender.newBuilder()
> >>>>>>> +        .withFileName("target/" + getClass().getName() + ".log")
> >>>>>>> +
> >> .withAppend(false).setName("File").setIgnoreExceptions(false)
> >>>>>>> +            .withBufferedIo(false)
> >>>>>>> +            .withBufferSize(4000)
> >>>>>>> +            .setConfiguration(config)
> >>>>>>> +            .build();
> >>>>>>> +        // @formatter:on
> >>>>>>> +        appender.start();
> >>>>>>> +        config.addAppender(appender);
> >>>>>>> +        ConfigurationTestUtils.updateLoggers(appender, config);
> >>>>>>> +        LogManager.getLogger().error("FOO MSG");
> >>>>>>> +    }
> >>>>>>> +}
> >>>>>>> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
> >>>>>>> index c3483bd..a9ec160 100644
> >>>>>>> --- a/src/changes/changes.xml
> >>>>>>> +++ b/src/changes/changes.xml
> >>>>>>> @@ -33,6 +33,9 @@
> >>>>>>>   <action issue="LOG4J2-2639" dev="rgoers" type="add">
> >>>>>>>     Add builder pattern to Logger interface.
> >>>>>>>   </action>
> >>>>>>> +      <action issue="LOG4J2-2673" dev="ggregory" type="fix"
> >>>> due-to="Yuichi Sugimura, Gary Gregory">
> >>>>>>> +        OutputStreamAppender.Builder ignores setFilter().
> >>>>>>> +      </action>
> >>>>>>> </release>
> >>>>>>> <release version="2.12.1" date="2019-08-06" description="GA Release
> >>>> 2.12.1">
> >>>>>>>   <action issue="LOG4J2-1946" dev="rgoers" type="fix" due-to="Igor
> >>>> Perelyotov">
> >>>>>>>
> >>>>>>>
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>
> >>>>
> >>>>
> >>
> >>
> >>
>
>
>

Re: [logging-log4j2] branch release-2.x updated: [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().

Posted by Ralph Goers <ra...@dslextreme.com>.
You may not be missing anything. If you don’t think it is a problem then just add the config items revapi spits out to the configuration. There are some there already so you can look at the justifications for those as examples.

Ralph

> On Aug 16, 2019, at 11:23 AM, Gary Gregory <ga...@gmail.com> wrote:
> 
> It looks like a bug in revapi to me: it does not know about type erasures.
> I created a new Maven project that depends on Log4j Core 2.12.1 with:
> 
> public class App
> {
>    public static void main( String[] args )
>    {
>        System.out.println( "Hello World!" );
>        Builder builder = OutputStreamAppender.newBuilder();
>    }
> }
> 
> Then I ran that class against 2.13.-SNAPSHOT Core without recompiling and
> it ran fine.
> 
> What am I missing?
> 
> Gary
> 
> On Thu, Aug 15, 2019 at 5:03 PM Ralph Goers <ra...@dslextreme.com>
> wrote:
> 
>> I believe you have not read this thread. I am not talking about the bug
>> you fixed. I am talking the compatibility breakage you created.
>> 
>> 1. The backward compatibility breakage only occurred on the release-2.x
>> branch because revapi is essentially disabled on master. Too much has
>> changed to bother keeping track.
>> 2. I haven’t seen any commit messages indicating you committed anything to
>> fix this.
>> 3. The build is still failing for me.  Try running mvn clean install
>> -DskipTests in log4j-core. It will break for you too.
>> 
>> Please look at the Jenkins build and fix the problems by either reverting
>> the breakage or by adding the recommended changes to revapi.json to
>> document why compatibility was broken.
>> 
>> Ralph
>> 
>> 
>>> On Aug 15, 2019, at 4:54 PM, Gary Gregory <ga...@gmail.com>
>> wrote:
>>> 
>>> I fixed it already in both branches.
>>> 
>>> Gary
>>> 
>>> On Thu, Aug 15, 2019, 10:42 Ralph Goers <ra...@dslextreme.com>
>> wrote:
>>> 
>>>> Gary,
>>>> 
>>>> Are you going to look into this?
>>>> 
>>>> Ralph
>>>> 
>>>>> On Aug 14, 2019, at 9:17 AM, Ralph Goers <ra...@dslextreme.com>
>>>> wrote:
>>>>> 
>>>>> Any update on this? I’d like my builds to work again.
>>>>> 
>>>>> Ralph
>>>>> 
>>>>>> On Aug 13, 2019, at 4:29 PM, Ralph Goers <ra...@dslextreme.com>
>>>> wrote:
>>>>>> 
>>>>>> Gary,
>>>>>> 
>>>>>> It seems this change broker compatibility. Please see the Jenkins
>>>> failure. You either need to resolve the code so compatibility is
>> maintained
>>>> or update revapi.json with the recommended changes.
>>>>>> 
>>>>>> Ralph
>>>>>> 
>>>>>>> On Aug 13, 2019, at 2:06 PM, ggregory@apache.org wrote:
>>>>>>> 
>>>>>>> This is an automated email from the ASF dual-hosted git repository.
>>>>>>> 
>>>>>>> ggregory pushed a commit to branch release-2.x
>>>>>>> in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
>>>>>>> 
>>>>>>> 
>>>>>>> The following commit(s) were added to refs/heads/release-2.x by this
>>>> push:
>>>>>>> new 4679a08  [LOG4J2-2673] OutputStreamAppender.Builder ignores
>>>> setFilter().
>>>>>>> 4679a08 is described below
>>>>>>> 
>>>>>>> commit 4679a08d4899350f7ee19d050d2a96783b748066
>>>>>>> Author: Gary Gregory <ga...@gmail.com>
>>>>>>> AuthorDate: Tue Aug 13 17:06:48 2019 -0400
>>>>>>> 
>>>>>>> [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
>>>>>>> 
>>>>>>> Also allow a null output stream for convenience instead of an NPE.
>>>>>>> ---
>>>>>>> .../log4j/core/appender/OutputStreamAppender.java  | 351
>>>> +++++++++++----------
>>>>>>> .../core/appender/OutputStreamAppenderTest.java    | 230
>> +++++++-------
>>>>>>> src/changes/changes.xml                            |   3 +
>>>>>>> 3 files changed, 302 insertions(+), 282 deletions(-)
>>>>>>> 
>>>>>>> diff --git
>>>> 
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>>>> 
>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>>>>>>> index 7dfd187..dc6f352 100644
>>>>>>> ---
>>>> 
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>>>>>>> +++
>>>> 
>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>>>>>>> @@ -1,174 +1,177 @@
>>>>>>> -/*
>>>>>>> - * 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.
>>>>>>> - */
>>>>>>> -package org.apache.logging.log4j.core.appender;
>>>>>>> -
>>>>>>> -import java.io.OutputStream;
>>>>>>> -import java.io.Serializable;
>>>>>>> -
>>>>>>> -import org.apache.logging.log4j.core.Appender;
>>>>>>> -import org.apache.logging.log4j.core.Core;
>>>>>>> -import org.apache.logging.log4j.core.Filter;
>>>>>>> -import org.apache.logging.log4j.core.Layout;
>>>>>>> -import org.apache.logging.log4j.core.config.Property;
>>>>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
>>>>>>> -import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>>>>>>> -import org.apache.logging.log4j.core.layout.PatternLayout;
>>>>>>> -import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
>>>>>>> -
>>>>>>> -/**
>>>>>>> - * Appends log events to a given output stream using a layout.
>>>>>>> - * <p>
>>>>>>> - * Character encoding is handled within the Layout.
>>>>>>> - * </p>
>>>>>>> - */
>>>>>>> -@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME,
>>>> elementType = Appender.ELEMENT_TYPE, printObject = true)
>>>>>>> -public final class OutputStreamAppender extends
>>>> AbstractOutputStreamAppender<OutputStreamManager> {
>>>>>>> -
>>>>>>> -    /**
>>>>>>> -     * Builds OutputStreamAppender instances.
>>>>>>> -     */
>>>>>>> -    public static class Builder<B extends Builder<B>> extends
>>>> AbstractOutputStreamAppender.Builder<B>
>>>>>>> -            implements
>>>> org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
>>>>>>> -
>>>>>>> -        private Filter filter;
>>>>>>> -
>>>>>>> -        private boolean follow = false;
>>>>>>> -
>>>>>>> -        private final boolean ignoreExceptions = true;
>>>>>>> -
>>>>>>> -        private OutputStream target;
>>>>>>> -
>>>>>>> -        @Override
>>>>>>> -        public OutputStreamAppender build() {
>>>>>>> -            final Layout<? extends Serializable> layout =
>> getLayout();
>>>>>>> -            final Layout<? extends Serializable> actualLayout =
>>>> layout == null ? PatternLayout.createDefaultLayout()
>>>>>>> -                    : layout;
>>>>>>> -            return new OutputStreamAppender(getName(), actualLayout,
>>>> filter, getManager(target, follow, actualLayout),
>>>>>>> -                    ignoreExceptions, getPropertyArray());
>>>>>>> -        }
>>>>>>> -
>>>>>>> -        public B setFollow(final boolean shouldFollow) {
>>>>>>> -            this.follow = shouldFollow;
>>>>>>> -            return asBuilder();
>>>>>>> -        }
>>>>>>> -
>>>>>>> -        public B setTarget(final OutputStream aTarget) {
>>>>>>> -            this.target = aTarget;
>>>>>>> -            return asBuilder();
>>>>>>> -        }
>>>>>>> -    }
>>>>>>> -
>>>>>>> -    /**
>>>>>>> -     * Holds data to pass to factory method.
>>>>>>> -     */
>>>>>>> -    private static class FactoryData {
>>>>>>> -        private final Layout<? extends Serializable> layout;
>>>>>>> -        private final String name;
>>>>>>> -        private final OutputStream os;
>>>>>>> -
>>>>>>> -        /**
>>>>>>> -         * Builds instances.
>>>>>>> -         *
>>>>>>> -         * @param os
>>>>>>> -         *            The OutputStream.
>>>>>>> -         * @param type
>>>>>>> -         *            The name of the target.
>>>>>>> -         * @param layout
>>>>>>> -         *            A Serializable layout
>>>>>>> -         */
>>>>>>> -        public FactoryData(final OutputStream os, final String type,
>>>> final Layout<? extends Serializable> layout) {
>>>>>>> -            this.os = os;
>>>>>>> -            this.name = type;
>>>>>>> -            this.layout = layout;
>>>>>>> -        }
>>>>>>> -    }
>>>>>>> -
>>>>>>> -    /**
>>>>>>> -     * Creates the manager.
>>>>>>> -     */
>>>>>>> -    private static class OutputStreamManagerFactory implements
>>>> ManagerFactory<OutputStreamManager, FactoryData> {
>>>>>>> -
>>>>>>> -        /**
>>>>>>> -         * Creates an OutputStreamManager.
>>>>>>> -         *
>>>>>>> -         * @param name
>>>>>>> -         *            The name of the entity to manage.
>>>>>>> -         * @param data
>>>>>>> -         *            The data required to create the entity.
>>>>>>> -         * @return The OutputStreamManager
>>>>>>> -         */
>>>>>>> -        @Override
>>>>>>> -        public OutputStreamManager createManager(final String name,
>>>> final FactoryData data) {
>>>>>>> -            return new OutputStreamManager(data.os, data.name,
>>>> data.layout, true);
>>>>>>> -        }
>>>>>>> -    }
>>>>>>> -
>>>>>>> -    private static OutputStreamManagerFactory factory = new
>>>> OutputStreamManagerFactory();
>>>>>>> -
>>>>>>> -    /**
>>>>>>> -     * Creates an OutputStream Appender.
>>>>>>> -     *
>>>>>>> -     * @param layout
>>>>>>> -     *            The layout to use or null to get the default
>> layout.
>>>>>>> -     * @param filter
>>>>>>> -     *            The Filter or null.
>>>>>>> -     * @param target
>>>>>>> -     *            an output stream.
>>>>>>> -     * @param follow
>>>>>>> -     *            If true will follow changes to the underlying
>>>> output stream.
>>>>>>> -     *            Use false as the default.
>>>>>>> -     * @param name
>>>>>>> -     *            The name of the Appender (required).
>>>>>>> -     * @param ignore
>>>>>>> -     *            If {@code "true"} (default) exceptions encountered
>>>> when
>>>>>>> -     *            appending events are logged; otherwise they are
>>>> propagated to
>>>>>>> -     *            the caller. Use true as the default.
>>>>>>> -     * @return The ConsoleAppender.
>>>>>>> -     */
>>>>>>> -    @PluginFactory
>>>>>>> -    public static OutputStreamAppender createAppender(Layout<?
>>>> extends Serializable> layout, final Filter filter,
>>>>>>> -            final OutputStream target, final String name, final
>>>> boolean follow, final boolean ignore) {
>>>>>>> -        if (name == null) {
>>>>>>> -            LOGGER.error("No name provided for
>> OutputStreamAppender");
>>>>>>> -            return null;
>>>>>>> -        }
>>>>>>> -        if (layout == null) {
>>>>>>> -            layout = PatternLayout.createDefaultLayout();
>>>>>>> -        }
>>>>>>> -        return new OutputStreamAppender(name, layout, filter,
>>>> getManager(target, follow, layout), ignore, null);
>>>>>>> -    }
>>>>>>> -
>>>>>>> -    private static OutputStreamManager getManager(final OutputStream
>>>> target, final boolean follow,
>>>>>>> -            final Layout<? extends Serializable> layout) {
>>>>>>> -        final OutputStream os = new CloseShieldOutputStream(target);
>>>>>>> -        final String managerName = target.getClass().getName() + "@"
>>>> + Integer.toHexString(target.hashCode()) + '.'
>>>>>>> -                + follow;
>>>>>>> -        return OutputStreamManager.getManager(managerName, new
>>>> FactoryData(os, managerName, layout), factory);
>>>>>>> -    }
>>>>>>> -
>>>>>>> -    @PluginBuilderFactory
>>>>>>> -    public static Builder newBuilder() {
>>>>>>> -        return new Builder();
>>>>>>> -    }
>>>>>>> -
>>>>>>> -    private OutputStreamAppender(final String name, final Layout<?
>>>> extends Serializable> layout, final Filter filter,
>>>>>>> -            final OutputStreamManager manager, final boolean
>>>> ignoreExceptions, final Property[] properties) {
>>>>>>> -        super(name, layout, filter, ignoreExceptions, true,
>>>> properties, manager);
>>>>>>> -    }
>>>>>>> -
>>>>>>> -}
>>>>>>> +/*
>>>>>>> + * 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.
>>>>>>> + */
>>>>>>> +package org.apache.logging.log4j.core.appender;
>>>>>>> +
>>>>>>> +import java.io.OutputStream;
>>>>>>> +import java.io.Serializable;
>>>>>>> +
>>>>>>> +import org.apache.logging.log4j.core.Appender;
>>>>>>> +import org.apache.logging.log4j.core.Core;
>>>>>>> +import org.apache.logging.log4j.core.Filter;
>>>>>>> +import org.apache.logging.log4j.core.Layout;
>>>>>>> +import org.apache.logging.log4j.core.config.Property;
>>>>>>> +import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>>>>> +import
>>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
>>>>>>> +import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>>>>>>> +import org.apache.logging.log4j.core.layout.PatternLayout;
>>>>>>> +import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
>>>>>>> +import org.apache.logging.log4j.core.util.NullOutputStream;
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * Appends log events to a given output stream using a layout.
>>>>>>> + * <p>
>>>>>>> + * Character encoding is handled within the Layout.
>>>>>>> + * </p>
>>>>>>> + */
>>>>>>> +@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME,
>>>> elementType = Appender.ELEMENT_TYPE, printObject = true)
>>>>>>> +public final class OutputStreamAppender extends
>>>> AbstractOutputStreamAppender<OutputStreamManager> {
>>>>>>> +
>>>>>>> +    /**
>>>>>>> +     * Builds OutputStreamAppender instances.
>>>>>>> +     *
>>>>>>> +     * @param <B>
>>>>>>> +     *            The type to build.
>>>>>>> +     */
>>>>>>> +    public static class Builder<B extends Builder<B>> extends
>>>> AbstractOutputStreamAppender.Builder<B>
>>>>>>> +            implements
>>>> org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
>>>>>>> +
>>>>>>> +        private boolean follow = false;
>>>>>>> +
>>>>>>> +        private final boolean ignoreExceptions = true;
>>>>>>> +
>>>>>>> +        private OutputStream target;
>>>>>>> +
>>>>>>> +        @Override
>>>>>>> +        public OutputStreamAppender build() {
>>>>>>> +            final Layout<? extends Serializable> layout =
>> getLayout();
>>>>>>> +            final Layout<? extends Serializable> actualLayout =
>>>> layout == null ? PatternLayout.createDefaultLayout()
>>>>>>> +                    : layout;
>>>>>>> +            return new OutputStreamAppender(getName(), actualLayout,
>>>> getFilter(), getManager(target, follow, actualLayout),
>>>>>>> +                    ignoreExceptions, getPropertyArray());
>>>>>>> +        }
>>>>>>> +
>>>>>>> +        public B setFollow(final boolean shouldFollow) {
>>>>>>> +            this.follow = shouldFollow;
>>>>>>> +            return asBuilder();
>>>>>>> +        }
>>>>>>> +
>>>>>>> +        public B setTarget(final OutputStream aTarget) {
>>>>>>> +            this.target = aTarget;
>>>>>>> +            return asBuilder();
>>>>>>> +        }
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    /**
>>>>>>> +     * Holds data to pass to factory method.
>>>>>>> +     */
>>>>>>> +    private static class FactoryData {
>>>>>>> +        private final Layout<? extends Serializable> layout;
>>>>>>> +        private final String name;
>>>>>>> +        private final OutputStream os;
>>>>>>> +
>>>>>>> +        /**
>>>>>>> +         * Builds instances.
>>>>>>> +         *
>>>>>>> +         * @param os
>>>>>>> +         *            The OutputStream.
>>>>>>> +         * @param type
>>>>>>> +         *            The name of the target.
>>>>>>> +         * @param layout
>>>>>>> +         *            A Serializable layout
>>>>>>> +         */
>>>>>>> +        public FactoryData(final OutputStream os, final String type,
>>>> final Layout<? extends Serializable> layout) {
>>>>>>> +            this.os = os;
>>>>>>> +            this.name = type;
>>>>>>> +            this.layout = layout;
>>>>>>> +        }
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    /**
>>>>>>> +     * Creates the manager.
>>>>>>> +     */
>>>>>>> +    private static class OutputStreamManagerFactory implements
>>>> ManagerFactory<OutputStreamManager, FactoryData> {
>>>>>>> +
>>>>>>> +        /**
>>>>>>> +         * Creates an OutputStreamManager.
>>>>>>> +         *
>>>>>>> +         * @param name
>>>>>>> +         *            The name of the entity to manage.
>>>>>>> +         * @param data
>>>>>>> +         *            The data required to create the entity.
>>>>>>> +         * @return The OutputStreamManager
>>>>>>> +         */
>>>>>>> +        @Override
>>>>>>> +        public OutputStreamManager createManager(final String name,
>>>> final FactoryData data) {
>>>>>>> +            return new OutputStreamManager(data.os, data.name,
>>>> data.layout, true);
>>>>>>> +        }
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    private static OutputStreamManagerFactory factory = new
>>>> OutputStreamManagerFactory();
>>>>>>> +
>>>>>>> +    /**
>>>>>>> +     * Creates an OutputStream Appender.
>>>>>>> +     *
>>>>>>> +     * @param layout
>>>>>>> +     *            The layout to use or null to get the default
>> layout.
>>>>>>> +     * @param filter
>>>>>>> +     *            The Filter or null.
>>>>>>> +     * @param target
>>>>>>> +     *            an output stream.
>>>>>>> +     * @param follow
>>>>>>> +     *            If true will follow changes to the underlying
>>>> output stream.
>>>>>>> +     *            Use false as the default.
>>>>>>> +     * @param name
>>>>>>> +     *            The name of the Appender (required).
>>>>>>> +     * @param ignore
>>>>>>> +     *            If {@code "true"} (default) exceptions encountered
>>>> when
>>>>>>> +     *            appending events are logged; otherwise they are
>>>> propagated to
>>>>>>> +     *            the caller. Use true as the default.
>>>>>>> +     * @return The ConsoleAppender.
>>>>>>> +     */
>>>>>>> +    @PluginFactory
>>>>>>> +    public static OutputStreamAppender createAppender(Layout<?
>>>> extends Serializable> layout, final Filter filter,
>>>>>>> +            final OutputStream target, final String name, final
>>>> boolean follow, final boolean ignore) {
>>>>>>> +        if (name == null) {
>>>>>>> +            LOGGER.error("No name provided for
>> OutputStreamAppender");
>>>>>>> +            return null;
>>>>>>> +        }
>>>>>>> +        if (layout == null) {
>>>>>>> +            layout = PatternLayout.createDefaultLayout();
>>>>>>> +        }
>>>>>>> +        return new OutputStreamAppender(name, layout, filter,
>>>> getManager(target, follow, layout), ignore, null);
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    private static OutputStreamManager getManager(final OutputStream
>>>> target, final boolean follow,
>>>>>>> +            final Layout<? extends Serializable> layout) {
>>>>>>> +        final OutputStream os = target == null ?
>>>> NullOutputStream.getInstance() : new CloseShieldOutputStream(target);
>>>>>>> +        final OutputStream targetRef = target == null ? os : target;
>>>>>>> +        final String managerName = targetRef.getClass().getName() +
>>>> "@" + Integer.toHexString(targetRef.hashCode())
>>>>>>> +                + '.' + follow;
>>>>>>> +        return OutputStreamManager.getManager(managerName, new
>>>> FactoryData(os, managerName, layout), factory);
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    @PluginBuilderFactory
>>>>>>> +    public static <B extends Builder<B>> B newBuilder() {
>>>>>>> +        return new Builder<B>().asBuilder();
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    private OutputStreamAppender(final String name, final Layout<?
>>>> extends Serializable> layout, final Filter filter,
>>>>>>> +            final OutputStreamManager manager, final boolean
>>>> ignoreExceptions, final Property[] properties) {
>>>>>>> +        super(name, layout, filter, ignoreExceptions, true,
>>>> properties, manager);
>>>>>>> +    }
>>>>>>> +
>>>>>>> +}
>>>>>>> diff --git
>>>> 
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>>>> 
>> b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>>>>>>> index 00af014..c1448bf 100644
>>>>>>> ---
>>>> 
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>>>>>>> +++
>>>> 
>> b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>>>>>>> @@ -1,108 +1,122 @@
>>>>>>> -/*
>>>>>>> - * 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.
>>>>>>> - */
>>>>>>> -package org.apache.logging.log4j.core.appender;
>>>>>>> -
>>>>>>> -import java.io.BufferedOutputStream;
>>>>>>> -import java.io.ByteArrayOutputStream;
>>>>>>> -import java.io.OutputStream;
>>>>>>> -import java.sql.SQLException;
>>>>>>> -
>>>>>>> -import org.apache.logging.log4j.LogManager;
>>>>>>> -import org.apache.logging.log4j.Logger;
>>>>>>> -import org.apache.logging.log4j.core.Appender;
>>>>>>> -import org.apache.logging.log4j.core.LoggerContext;
>>>>>>> -import org.apache.logging.log4j.core.config.Configuration;
>>>>>>> -import org.apache.logging.log4j.core.layout.PatternLayout;
>>>>>>> -import org.junit.Assert;
>>>>>>> -import org.junit.Rule;
>>>>>>> -import org.junit.Test;
>>>>>>> -import org.junit.rules.TestName;
>>>>>>> -
>>>>>>> -/**
>>>>>>> - * Tests {@link OutputStreamAppender}.
>>>>>>> - */
>>>>>>> -public class OutputStreamAppenderTest {
>>>>>>> -
>>>>>>> -    private static final String TEST_MSG = "FOO ERROR";
>>>>>>> -
>>>>>>> -    @Rule
>>>>>>> -    public TestName testName = new TestName();
>>>>>>> -
>>>>>>> -    private String getName(final OutputStream out) {
>>>>>>> -        return out.getClass().getSimpleName() + "." +
>>>> testName.getMethodName();
>>>>>>> -    }
>>>>>>> -
>>>>>>> -    /**
>>>>>>> -     * Tests that you can add an output stream appender dynamically.
>>>>>>> -     */
>>>>>>> -    private void addAppender(final OutputStream outputStream, final
>>>> String outputStreamName) {
>>>>>>> -        final LoggerContext context =
>> LoggerContext.getContext(false);
>>>>>>> -        final Configuration config = context.getConfiguration();
>>>>>>> -        final PatternLayout layout =
>>>> PatternLayout.createDefaultLayout(config);
>>>>>>> -        final Appender appender =
>>>> OutputStreamAppender.createAppender(layout, null, outputStream,
>>>> outputStreamName, false, true);
>>>>>>> -        appender.start();
>>>>>>> -        config.addAppender(appender);
>>>>>>> -        ConfigurationTestUtils.updateLoggers(appender, config);
>>>>>>> -    }
>>>>>>> -
>>>>>>> -    @Test
>>>>>>> -    public void testOutputStreamAppenderToBufferedOutputStream()
>>>> throws SQLException {
>>>>>>> -        final ByteArrayOutputStream out = new
>> ByteArrayOutputStream();
>>>>>>> -        final OutputStream os = new BufferedOutputStream(out);
>>>>>>> -        final String name = getName(out);
>>>>>>> -        final Logger logger = LogManager.getLogger(name);
>>>>>>> -        addAppender(os, name);
>>>>>>> -        logger.error(TEST_MSG);
>>>>>>> -        final String actual = out.toString();
>>>>>>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>>>>>>> -    }
>>>>>>> -
>>>>>>> -    @Test
>>>>>>> -    public void testOutputStreamAppenderToByteArrayOutputStream()
>>>> throws SQLException {
>>>>>>> -        final OutputStream out = new ByteArrayOutputStream();
>>>>>>> -        final String name = getName(out);
>>>>>>> -        final Logger logger = LogManager.getLogger(name);
>>>>>>> -        addAppender(out, name);
>>>>>>> -        logger.error(TEST_MSG);
>>>>>>> -        final String actual = out.toString();
>>>>>>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>>>>>>> -    }
>>>>>>> -
>>>>>>> -    /**
>>>>>>> -     * Validates that the code pattern we use to add an appender on
>>>> the fly
>>>>>>> -     * works with a basic appender that is not the new OutputStream
>>>> appender or
>>>>>>> -     * new Writer appender.
>>>>>>> -     */
>>>>>>> -    @Test
>>>>>>> -    public void testUpdatePatternWithFileAppender() {
>>>>>>> -        final LoggerContext ctx = (LoggerContext)
>>>> LogManager.getContext(false);
>>>>>>> -        final Configuration config = ctx.getConfiguration();
>>>>>>> -        // @formatter:off
>>>>>>> -        final Appender appender = FileAppender.newBuilder()
>>>>>>> -        .withFileName("target/" + getClass().getName() + ".log")
>>>>>>> -
>> .withAppend(false).setName("File").setIgnoreExceptions(false)
>>>>>>> -            .withBufferedIo(false)
>>>>>>> -            .withBufferSize(4000)
>>>>>>> -            .setConfiguration(config)
>>>>>>> -            .build();
>>>>>>> -        // @formatter:on
>>>>>>> -        appender.start();
>>>>>>> -        config.addAppender(appender);
>>>>>>> -        ConfigurationTestUtils.updateLoggers(appender, config);
>>>>>>> -        LogManager.getLogger().error("FOO MSG");
>>>>>>> -    }
>>>>>>> -}
>>>>>>> +/*
>>>>>>> + * 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.
>>>>>>> + */
>>>>>>> +package org.apache.logging.log4j.core.appender;
>>>>>>> +
>>>>>>> +import java.io.BufferedOutputStream;
>>>>>>> +import java.io.ByteArrayOutputStream;
>>>>>>> +import java.io.OutputStream;
>>>>>>> +import java.sql.SQLException;
>>>>>>> +
>>>>>>> +import org.apache.logging.log4j.LogManager;
>>>>>>> +import org.apache.logging.log4j.Logger;
>>>>>>> +import org.apache.logging.log4j.core.Appender;
>>>>>>> +import org.apache.logging.log4j.core.LoggerContext;
>>>>>>> +import org.apache.logging.log4j.core.config.Configuration;
>>>>>>> +import org.apache.logging.log4j.core.filter.NoMarkerFilter;
>>>>>>> +import org.apache.logging.log4j.core.layout.PatternLayout;
>>>>>>> +import org.junit.Assert;
>>>>>>> +import org.junit.Rule;
>>>>>>> +import org.junit.Test;
>>>>>>> +import org.junit.rules.TestName;
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * Tests {@link OutputStreamAppender}.
>>>>>>> + */
>>>>>>> +public class OutputStreamAppenderTest {
>>>>>>> +
>>>>>>> +    private static final String TEST_MSG = "FOO ERROR";
>>>>>>> +
>>>>>>> +    @Rule
>>>>>>> +    public TestName testName = new TestName();
>>>>>>> +
>>>>>>> +    private String getName(final OutputStream out) {
>>>>>>> +        return out.getClass().getSimpleName() + "." +
>>>> testName.getMethodName();
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    /**
>>>>>>> +     * Tests that you can add an output stream appender dynamically.
>>>>>>> +     */
>>>>>>> +    private void addAppender(final OutputStream outputStream, final
>>>> String outputStreamName) {
>>>>>>> +        final LoggerContext context =
>> LoggerContext.getContext(false);
>>>>>>> +        final Configuration config = context.getConfiguration();
>>>>>>> +        final PatternLayout layout =
>>>> PatternLayout.createDefaultLayout(config);
>>>>>>> +        final Appender appender =
>>>> OutputStreamAppender.createAppender(layout, null, outputStream,
>>>> outputStreamName, false, true);
>>>>>>> +        appender.start();
>>>>>>> +        config.addAppender(appender);
>>>>>>> +        ConfigurationTestUtils.updateLoggers(appender, config);
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    @Test
>>>>>>> +    public void testBuildFilter() {
>>>>>>> +        final NoMarkerFilter filter =
>>>> NoMarkerFilter.newBuilder().build();
>>>>>>> +        // @formatter:off
>>>>>>> +        final OutputStreamAppender.Builder builder =
>>>> OutputStreamAppender.newBuilder()
>>>>>>> +                .setName("test")
>>>>>>> +                .setFilter(filter);
>>>>>>> +        // @formatter:on
>>>>>>> +        Assert.assertEquals(filter, builder.getFilter());
>>>>>>> +        final OutputStreamAppender appender = builder.build();
>>>>>>> +        Assert.assertEquals(filter, appender.getFilter());
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    @Test
>>>>>>> +    public void testOutputStreamAppenderToBufferedOutputStream()
>>>> throws SQLException {
>>>>>>> +        final ByteArrayOutputStream out = new
>> ByteArrayOutputStream();
>>>>>>> +        final OutputStream os = new BufferedOutputStream(out);
>>>>>>> +        final String name = getName(out);
>>>>>>> +        final Logger logger = LogManager.getLogger(name);
>>>>>>> +        addAppender(os, name);
>>>>>>> +        logger.error(TEST_MSG);
>>>>>>> +        final String actual = out.toString();
>>>>>>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    @Test
>>>>>>> +    public void testOutputStreamAppenderToByteArrayOutputStream()
>>>> throws SQLException {
>>>>>>> +        final OutputStream out = new ByteArrayOutputStream();
>>>>>>> +        final String name = getName(out);
>>>>>>> +        final Logger logger = LogManager.getLogger(name);
>>>>>>> +        addAppender(out, name);
>>>>>>> +        logger.error(TEST_MSG);
>>>>>>> +        final String actual = out.toString();
>>>>>>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    /**
>>>>>>> +     * Validates that the code pattern we use to add an appender on
>>>> the fly
>>>>>>> +     * works with a basic appender that is not the new OutputStream
>>>> appender or
>>>>>>> +     * new Writer appender.
>>>>>>> +     */
>>>>>>> +    @Test
>>>>>>> +    public void testUpdatePatternWithFileAppender() {
>>>>>>> +        final LoggerContext ctx = (LoggerContext)
>>>> LogManager.getContext(false);
>>>>>>> +        final Configuration config = ctx.getConfiguration();
>>>>>>> +        // @formatter:off
>>>>>>> +        final Appender appender = FileAppender.newBuilder()
>>>>>>> +        .withFileName("target/" + getClass().getName() + ".log")
>>>>>>> +
>> .withAppend(false).setName("File").setIgnoreExceptions(false)
>>>>>>> +            .withBufferedIo(false)
>>>>>>> +            .withBufferSize(4000)
>>>>>>> +            .setConfiguration(config)
>>>>>>> +            .build();
>>>>>>> +        // @formatter:on
>>>>>>> +        appender.start();
>>>>>>> +        config.addAppender(appender);
>>>>>>> +        ConfigurationTestUtils.updateLoggers(appender, config);
>>>>>>> +        LogManager.getLogger().error("FOO MSG");
>>>>>>> +    }
>>>>>>> +}
>>>>>>> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
>>>>>>> index c3483bd..a9ec160 100644
>>>>>>> --- a/src/changes/changes.xml
>>>>>>> +++ b/src/changes/changes.xml
>>>>>>> @@ -33,6 +33,9 @@
>>>>>>>   <action issue="LOG4J2-2639" dev="rgoers" type="add">
>>>>>>>     Add builder pattern to Logger interface.
>>>>>>>   </action>
>>>>>>> +      <action issue="LOG4J2-2673" dev="ggregory" type="fix"
>>>> due-to="Yuichi Sugimura, Gary Gregory">
>>>>>>> +        OutputStreamAppender.Builder ignores setFilter().
>>>>>>> +      </action>
>>>>>>> </release>
>>>>>>> <release version="2.12.1" date="2019-08-06" description="GA Release
>>>> 2.12.1">
>>>>>>>   <action issue="LOG4J2-1946" dev="rgoers" type="fix" due-to="Igor
>>>> Perelyotov">
>>>>>>> 
>>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>> 
>>>> 
>>>> 
>> 
>> 
>> 



Re: [logging-log4j2] branch release-2.x updated: [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().

Posted by Gary Gregory <ga...@gmail.com>.
It looks like a bug in revapi to me: it does not know about type erasures.
I created a new Maven project that depends on Log4j Core 2.12.1 with:

public class App
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
        Builder builder = OutputStreamAppender.newBuilder();
    }
}

Then I ran that class against 2.13.-SNAPSHOT Core without recompiling and
it ran fine.

What am I missing?

Gary

On Thu, Aug 15, 2019 at 5:03 PM Ralph Goers <ra...@dslextreme.com>
wrote:

> I believe you have not read this thread. I am not talking about the bug
> you fixed. I am talking the compatibility breakage you created.
>
> 1. The backward compatibility breakage only occurred on the release-2.x
> branch because revapi is essentially disabled on master. Too much has
> changed to bother keeping track.
> 2. I haven’t seen any commit messages indicating you committed anything to
> fix this.
> 3. The build is still failing for me.  Try running mvn clean install
> -DskipTests in log4j-core. It will break for you too.
>
> Please look at the Jenkins build and fix the problems by either reverting
> the breakage or by adding the recommended changes to revapi.json to
> document why compatibility was broken.
>
> Ralph
>
>
> > On Aug 15, 2019, at 4:54 PM, Gary Gregory <ga...@gmail.com>
> wrote:
> >
> > I fixed it already in both branches.
> >
> > Gary
> >
> > On Thu, Aug 15, 2019, 10:42 Ralph Goers <ra...@dslextreme.com>
> wrote:
> >
> >> Gary,
> >>
> >> Are you going to look into this?
> >>
> >> Ralph
> >>
> >>> On Aug 14, 2019, at 9:17 AM, Ralph Goers <ra...@dslextreme.com>
> >> wrote:
> >>>
> >>> Any update on this? I’d like my builds to work again.
> >>>
> >>> Ralph
> >>>
> >>>> On Aug 13, 2019, at 4:29 PM, Ralph Goers <ra...@dslextreme.com>
> >> wrote:
> >>>>
> >>>> Gary,
> >>>>
> >>>> It seems this change broker compatibility. Please see the Jenkins
> >> failure. You either need to resolve the code so compatibility is
> maintained
> >> or update revapi.json with the recommended changes.
> >>>>
> >>>> Ralph
> >>>>
> >>>>> On Aug 13, 2019, at 2:06 PM, ggregory@apache.org wrote:
> >>>>>
> >>>>> This is an automated email from the ASF dual-hosted git repository.
> >>>>>
> >>>>> ggregory pushed a commit to branch release-2.x
> >>>>> in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
> >>>>>
> >>>>>
> >>>>> The following commit(s) were added to refs/heads/release-2.x by this
> >> push:
> >>>>>  new 4679a08  [LOG4J2-2673] OutputStreamAppender.Builder ignores
> >> setFilter().
> >>>>> 4679a08 is described below
> >>>>>
> >>>>> commit 4679a08d4899350f7ee19d050d2a96783b748066
> >>>>> Author: Gary Gregory <ga...@gmail.com>
> >>>>> AuthorDate: Tue Aug 13 17:06:48 2019 -0400
> >>>>>
> >>>>> [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
> >>>>>
> >>>>> Also allow a null output stream for convenience instead of an NPE.
> >>>>> ---
> >>>>> .../log4j/core/appender/OutputStreamAppender.java  | 351
> >> +++++++++++----------
> >>>>> .../core/appender/OutputStreamAppenderTest.java    | 230
> +++++++-------
> >>>>> src/changes/changes.xml                            |   3 +
> >>>>> 3 files changed, 302 insertions(+), 282 deletions(-)
> >>>>>
> >>>>> diff --git
> >>
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>>>> index 7dfd187..dc6f352 100644
> >>>>> ---
> >>
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>>>> +++
> >>
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>>>> @@ -1,174 +1,177 @@
> >>>>> -/*
> >>>>> - * 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.
> >>>>> - */
> >>>>> -package org.apache.logging.log4j.core.appender;
> >>>>> -
> >>>>> -import java.io.OutputStream;
> >>>>> -import java.io.Serializable;
> >>>>> -
> >>>>> -import org.apache.logging.log4j.core.Appender;
> >>>>> -import org.apache.logging.log4j.core.Core;
> >>>>> -import org.apache.logging.log4j.core.Filter;
> >>>>> -import org.apache.logging.log4j.core.Layout;
> >>>>> -import org.apache.logging.log4j.core.config.Property;
> >>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> >>>>> -import
> >> org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
> >>>>> -import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> >>>>> -import org.apache.logging.log4j.core.layout.PatternLayout;
> >>>>> -import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
> >>>>> -
> >>>>> -/**
> >>>>> - * Appends log events to a given output stream using a layout.
> >>>>> - * <p>
> >>>>> - * Character encoding is handled within the Layout.
> >>>>> - * </p>
> >>>>> - */
> >>>>> -@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME,
> >> elementType = Appender.ELEMENT_TYPE, printObject = true)
> >>>>> -public final class OutputStreamAppender extends
> >> AbstractOutputStreamAppender<OutputStreamManager> {
> >>>>> -
> >>>>> -    /**
> >>>>> -     * Builds OutputStreamAppender instances.
> >>>>> -     */
> >>>>> -    public static class Builder<B extends Builder<B>> extends
> >> AbstractOutputStreamAppender.Builder<B>
> >>>>> -            implements
> >> org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
> >>>>> -
> >>>>> -        private Filter filter;
> >>>>> -
> >>>>> -        private boolean follow = false;
> >>>>> -
> >>>>> -        private final boolean ignoreExceptions = true;
> >>>>> -
> >>>>> -        private OutputStream target;
> >>>>> -
> >>>>> -        @Override
> >>>>> -        public OutputStreamAppender build() {
> >>>>> -            final Layout<? extends Serializable> layout =
> getLayout();
> >>>>> -            final Layout<? extends Serializable> actualLayout =
> >> layout == null ? PatternLayout.createDefaultLayout()
> >>>>> -                    : layout;
> >>>>> -            return new OutputStreamAppender(getName(), actualLayout,
> >> filter, getManager(target, follow, actualLayout),
> >>>>> -                    ignoreExceptions, getPropertyArray());
> >>>>> -        }
> >>>>> -
> >>>>> -        public B setFollow(final boolean shouldFollow) {
> >>>>> -            this.follow = shouldFollow;
> >>>>> -            return asBuilder();
> >>>>> -        }
> >>>>> -
> >>>>> -        public B setTarget(final OutputStream aTarget) {
> >>>>> -            this.target = aTarget;
> >>>>> -            return asBuilder();
> >>>>> -        }
> >>>>> -    }
> >>>>> -
> >>>>> -    /**
> >>>>> -     * Holds data to pass to factory method.
> >>>>> -     */
> >>>>> -    private static class FactoryData {
> >>>>> -        private final Layout<? extends Serializable> layout;
> >>>>> -        private final String name;
> >>>>> -        private final OutputStream os;
> >>>>> -
> >>>>> -        /**
> >>>>> -         * Builds instances.
> >>>>> -         *
> >>>>> -         * @param os
> >>>>> -         *            The OutputStream.
> >>>>> -         * @param type
> >>>>> -         *            The name of the target.
> >>>>> -         * @param layout
> >>>>> -         *            A Serializable layout
> >>>>> -         */
> >>>>> -        public FactoryData(final OutputStream os, final String type,
> >> final Layout<? extends Serializable> layout) {
> >>>>> -            this.os = os;
> >>>>> -            this.name = type;
> >>>>> -            this.layout = layout;
> >>>>> -        }
> >>>>> -    }
> >>>>> -
> >>>>> -    /**
> >>>>> -     * Creates the manager.
> >>>>> -     */
> >>>>> -    private static class OutputStreamManagerFactory implements
> >> ManagerFactory<OutputStreamManager, FactoryData> {
> >>>>> -
> >>>>> -        /**
> >>>>> -         * Creates an OutputStreamManager.
> >>>>> -         *
> >>>>> -         * @param name
> >>>>> -         *            The name of the entity to manage.
> >>>>> -         * @param data
> >>>>> -         *            The data required to create the entity.
> >>>>> -         * @return The OutputStreamManager
> >>>>> -         */
> >>>>> -        @Override
> >>>>> -        public OutputStreamManager createManager(final String name,
> >> final FactoryData data) {
> >>>>> -            return new OutputStreamManager(data.os, data.name,
> >> data.layout, true);
> >>>>> -        }
> >>>>> -    }
> >>>>> -
> >>>>> -    private static OutputStreamManagerFactory factory = new
> >> OutputStreamManagerFactory();
> >>>>> -
> >>>>> -    /**
> >>>>> -     * Creates an OutputStream Appender.
> >>>>> -     *
> >>>>> -     * @param layout
> >>>>> -     *            The layout to use or null to get the default
> layout.
> >>>>> -     * @param filter
> >>>>> -     *            The Filter or null.
> >>>>> -     * @param target
> >>>>> -     *            an output stream.
> >>>>> -     * @param follow
> >>>>> -     *            If true will follow changes to the underlying
> >> output stream.
> >>>>> -     *            Use false as the default.
> >>>>> -     * @param name
> >>>>> -     *            The name of the Appender (required).
> >>>>> -     * @param ignore
> >>>>> -     *            If {@code "true"} (default) exceptions encountered
> >> when
> >>>>> -     *            appending events are logged; otherwise they are
> >> propagated to
> >>>>> -     *            the caller. Use true as the default.
> >>>>> -     * @return The ConsoleAppender.
> >>>>> -     */
> >>>>> -    @PluginFactory
> >>>>> -    public static OutputStreamAppender createAppender(Layout<?
> >> extends Serializable> layout, final Filter filter,
> >>>>> -            final OutputStream target, final String name, final
> >> boolean follow, final boolean ignore) {
> >>>>> -        if (name == null) {
> >>>>> -            LOGGER.error("No name provided for
> OutputStreamAppender");
> >>>>> -            return null;
> >>>>> -        }
> >>>>> -        if (layout == null) {
> >>>>> -            layout = PatternLayout.createDefaultLayout();
> >>>>> -        }
> >>>>> -        return new OutputStreamAppender(name, layout, filter,
> >> getManager(target, follow, layout), ignore, null);
> >>>>> -    }
> >>>>> -
> >>>>> -    private static OutputStreamManager getManager(final OutputStream
> >> target, final boolean follow,
> >>>>> -            final Layout<? extends Serializable> layout) {
> >>>>> -        final OutputStream os = new CloseShieldOutputStream(target);
> >>>>> -        final String managerName = target.getClass().getName() + "@"
> >> + Integer.toHexString(target.hashCode()) + '.'
> >>>>> -                + follow;
> >>>>> -        return OutputStreamManager.getManager(managerName, new
> >> FactoryData(os, managerName, layout), factory);
> >>>>> -    }
> >>>>> -
> >>>>> -    @PluginBuilderFactory
> >>>>> -    public static Builder newBuilder() {
> >>>>> -        return new Builder();
> >>>>> -    }
> >>>>> -
> >>>>> -    private OutputStreamAppender(final String name, final Layout<?
> >> extends Serializable> layout, final Filter filter,
> >>>>> -            final OutputStreamManager manager, final boolean
> >> ignoreExceptions, final Property[] properties) {
> >>>>> -        super(name, layout, filter, ignoreExceptions, true,
> >> properties, manager);
> >>>>> -    }
> >>>>> -
> >>>>> -}
> >>>>> +/*
> >>>>> + * 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.
> >>>>> + */
> >>>>> +package org.apache.logging.log4j.core.appender;
> >>>>> +
> >>>>> +import java.io.OutputStream;
> >>>>> +import java.io.Serializable;
> >>>>> +
> >>>>> +import org.apache.logging.log4j.core.Appender;
> >>>>> +import org.apache.logging.log4j.core.Core;
> >>>>> +import org.apache.logging.log4j.core.Filter;
> >>>>> +import org.apache.logging.log4j.core.Layout;
> >>>>> +import org.apache.logging.log4j.core.config.Property;
> >>>>> +import org.apache.logging.log4j.core.config.plugins.Plugin;
> >>>>> +import
> >> org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
> >>>>> +import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> >>>>> +import org.apache.logging.log4j.core.layout.PatternLayout;
> >>>>> +import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
> >>>>> +import org.apache.logging.log4j.core.util.NullOutputStream;
> >>>>> +
> >>>>> +/**
> >>>>> + * Appends log events to a given output stream using a layout.
> >>>>> + * <p>
> >>>>> + * Character encoding is handled within the Layout.
> >>>>> + * </p>
> >>>>> + */
> >>>>> +@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME,
> >> elementType = Appender.ELEMENT_TYPE, printObject = true)
> >>>>> +public final class OutputStreamAppender extends
> >> AbstractOutputStreamAppender<OutputStreamManager> {
> >>>>> +
> >>>>> +    /**
> >>>>> +     * Builds OutputStreamAppender instances.
> >>>>> +     *
> >>>>> +     * @param <B>
> >>>>> +     *            The type to build.
> >>>>> +     */
> >>>>> +    public static class Builder<B extends Builder<B>> extends
> >> AbstractOutputStreamAppender.Builder<B>
> >>>>> +            implements
> >> org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
> >>>>> +
> >>>>> +        private boolean follow = false;
> >>>>> +
> >>>>> +        private final boolean ignoreExceptions = true;
> >>>>> +
> >>>>> +        private OutputStream target;
> >>>>> +
> >>>>> +        @Override
> >>>>> +        public OutputStreamAppender build() {
> >>>>> +            final Layout<? extends Serializable> layout =
> getLayout();
> >>>>> +            final Layout<? extends Serializable> actualLayout =
> >> layout == null ? PatternLayout.createDefaultLayout()
> >>>>> +                    : layout;
> >>>>> +            return new OutputStreamAppender(getName(), actualLayout,
> >> getFilter(), getManager(target, follow, actualLayout),
> >>>>> +                    ignoreExceptions, getPropertyArray());
> >>>>> +        }
> >>>>> +
> >>>>> +        public B setFollow(final boolean shouldFollow) {
> >>>>> +            this.follow = shouldFollow;
> >>>>> +            return asBuilder();
> >>>>> +        }
> >>>>> +
> >>>>> +        public B setTarget(final OutputStream aTarget) {
> >>>>> +            this.target = aTarget;
> >>>>> +            return asBuilder();
> >>>>> +        }
> >>>>> +    }
> >>>>> +
> >>>>> +    /**
> >>>>> +     * Holds data to pass to factory method.
> >>>>> +     */
> >>>>> +    private static class FactoryData {
> >>>>> +        private final Layout<? extends Serializable> layout;
> >>>>> +        private final String name;
> >>>>> +        private final OutputStream os;
> >>>>> +
> >>>>> +        /**
> >>>>> +         * Builds instances.
> >>>>> +         *
> >>>>> +         * @param os
> >>>>> +         *            The OutputStream.
> >>>>> +         * @param type
> >>>>> +         *            The name of the target.
> >>>>> +         * @param layout
> >>>>> +         *            A Serializable layout
> >>>>> +         */
> >>>>> +        public FactoryData(final OutputStream os, final String type,
> >> final Layout<? extends Serializable> layout) {
> >>>>> +            this.os = os;
> >>>>> +            this.name = type;
> >>>>> +            this.layout = layout;
> >>>>> +        }
> >>>>> +    }
> >>>>> +
> >>>>> +    /**
> >>>>> +     * Creates the manager.
> >>>>> +     */
> >>>>> +    private static class OutputStreamManagerFactory implements
> >> ManagerFactory<OutputStreamManager, FactoryData> {
> >>>>> +
> >>>>> +        /**
> >>>>> +         * Creates an OutputStreamManager.
> >>>>> +         *
> >>>>> +         * @param name
> >>>>> +         *            The name of the entity to manage.
> >>>>> +         * @param data
> >>>>> +         *            The data required to create the entity.
> >>>>> +         * @return The OutputStreamManager
> >>>>> +         */
> >>>>> +        @Override
> >>>>> +        public OutputStreamManager createManager(final String name,
> >> final FactoryData data) {
> >>>>> +            return new OutputStreamManager(data.os, data.name,
> >> data.layout, true);
> >>>>> +        }
> >>>>> +    }
> >>>>> +
> >>>>> +    private static OutputStreamManagerFactory factory = new
> >> OutputStreamManagerFactory();
> >>>>> +
> >>>>> +    /**
> >>>>> +     * Creates an OutputStream Appender.
> >>>>> +     *
> >>>>> +     * @param layout
> >>>>> +     *            The layout to use or null to get the default
> layout.
> >>>>> +     * @param filter
> >>>>> +     *            The Filter or null.
> >>>>> +     * @param target
> >>>>> +     *            an output stream.
> >>>>> +     * @param follow
> >>>>> +     *            If true will follow changes to the underlying
> >> output stream.
> >>>>> +     *            Use false as the default.
> >>>>> +     * @param name
> >>>>> +     *            The name of the Appender (required).
> >>>>> +     * @param ignore
> >>>>> +     *            If {@code "true"} (default) exceptions encountered
> >> when
> >>>>> +     *            appending events are logged; otherwise they are
> >> propagated to
> >>>>> +     *            the caller. Use true as the default.
> >>>>> +     * @return The ConsoleAppender.
> >>>>> +     */
> >>>>> +    @PluginFactory
> >>>>> +    public static OutputStreamAppender createAppender(Layout<?
> >> extends Serializable> layout, final Filter filter,
> >>>>> +            final OutputStream target, final String name, final
> >> boolean follow, final boolean ignore) {
> >>>>> +        if (name == null) {
> >>>>> +            LOGGER.error("No name provided for
> OutputStreamAppender");
> >>>>> +            return null;
> >>>>> +        }
> >>>>> +        if (layout == null) {
> >>>>> +            layout = PatternLayout.createDefaultLayout();
> >>>>> +        }
> >>>>> +        return new OutputStreamAppender(name, layout, filter,
> >> getManager(target, follow, layout), ignore, null);
> >>>>> +    }
> >>>>> +
> >>>>> +    private static OutputStreamManager getManager(final OutputStream
> >> target, final boolean follow,
> >>>>> +            final Layout<? extends Serializable> layout) {
> >>>>> +        final OutputStream os = target == null ?
> >> NullOutputStream.getInstance() : new CloseShieldOutputStream(target);
> >>>>> +        final OutputStream targetRef = target == null ? os : target;
> >>>>> +        final String managerName = targetRef.getClass().getName() +
> >> "@" + Integer.toHexString(targetRef.hashCode())
> >>>>> +                + '.' + follow;
> >>>>> +        return OutputStreamManager.getManager(managerName, new
> >> FactoryData(os, managerName, layout), factory);
> >>>>> +    }
> >>>>> +
> >>>>> +    @PluginBuilderFactory
> >>>>> +    public static <B extends Builder<B>> B newBuilder() {
> >>>>> +        return new Builder<B>().asBuilder();
> >>>>> +    }
> >>>>> +
> >>>>> +    private OutputStreamAppender(final String name, final Layout<?
> >> extends Serializable> layout, final Filter filter,
> >>>>> +            final OutputStreamManager manager, final boolean
> >> ignoreExceptions, final Property[] properties) {
> >>>>> +        super(name, layout, filter, ignoreExceptions, true,
> >> properties, manager);
> >>>>> +    }
> >>>>> +
> >>>>> +}
> >>>>> diff --git
> >>
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>
> b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>>>> index 00af014..c1448bf 100644
> >>>>> ---
> >>
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>>>> +++
> >>
> b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>>>> @@ -1,108 +1,122 @@
> >>>>> -/*
> >>>>> - * 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.
> >>>>> - */
> >>>>> -package org.apache.logging.log4j.core.appender;
> >>>>> -
> >>>>> -import java.io.BufferedOutputStream;
> >>>>> -import java.io.ByteArrayOutputStream;
> >>>>> -import java.io.OutputStream;
> >>>>> -import java.sql.SQLException;
> >>>>> -
> >>>>> -import org.apache.logging.log4j.LogManager;
> >>>>> -import org.apache.logging.log4j.Logger;
> >>>>> -import org.apache.logging.log4j.core.Appender;
> >>>>> -import org.apache.logging.log4j.core.LoggerContext;
> >>>>> -import org.apache.logging.log4j.core.config.Configuration;
> >>>>> -import org.apache.logging.log4j.core.layout.PatternLayout;
> >>>>> -import org.junit.Assert;
> >>>>> -import org.junit.Rule;
> >>>>> -import org.junit.Test;
> >>>>> -import org.junit.rules.TestName;
> >>>>> -
> >>>>> -/**
> >>>>> - * Tests {@link OutputStreamAppender}.
> >>>>> - */
> >>>>> -public class OutputStreamAppenderTest {
> >>>>> -
> >>>>> -    private static final String TEST_MSG = "FOO ERROR";
> >>>>> -
> >>>>> -    @Rule
> >>>>> -    public TestName testName = new TestName();
> >>>>> -
> >>>>> -    private String getName(final OutputStream out) {
> >>>>> -        return out.getClass().getSimpleName() + "." +
> >> testName.getMethodName();
> >>>>> -    }
> >>>>> -
> >>>>> -    /**
> >>>>> -     * Tests that you can add an output stream appender dynamically.
> >>>>> -     */
> >>>>> -    private void addAppender(final OutputStream outputStream, final
> >> String outputStreamName) {
> >>>>> -        final LoggerContext context =
> LoggerContext.getContext(false);
> >>>>> -        final Configuration config = context.getConfiguration();
> >>>>> -        final PatternLayout layout =
> >> PatternLayout.createDefaultLayout(config);
> >>>>> -        final Appender appender =
> >> OutputStreamAppender.createAppender(layout, null, outputStream,
> >> outputStreamName, false, true);
> >>>>> -        appender.start();
> >>>>> -        config.addAppender(appender);
> >>>>> -        ConfigurationTestUtils.updateLoggers(appender, config);
> >>>>> -    }
> >>>>> -
> >>>>> -    @Test
> >>>>> -    public void testOutputStreamAppenderToBufferedOutputStream()
> >> throws SQLException {
> >>>>> -        final ByteArrayOutputStream out = new
> ByteArrayOutputStream();
> >>>>> -        final OutputStream os = new BufferedOutputStream(out);
> >>>>> -        final String name = getName(out);
> >>>>> -        final Logger logger = LogManager.getLogger(name);
> >>>>> -        addAppender(os, name);
> >>>>> -        logger.error(TEST_MSG);
> >>>>> -        final String actual = out.toString();
> >>>>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>>>> -    }
> >>>>> -
> >>>>> -    @Test
> >>>>> -    public void testOutputStreamAppenderToByteArrayOutputStream()
> >> throws SQLException {
> >>>>> -        final OutputStream out = new ByteArrayOutputStream();
> >>>>> -        final String name = getName(out);
> >>>>> -        final Logger logger = LogManager.getLogger(name);
> >>>>> -        addAppender(out, name);
> >>>>> -        logger.error(TEST_MSG);
> >>>>> -        final String actual = out.toString();
> >>>>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>>>> -    }
> >>>>> -
> >>>>> -    /**
> >>>>> -     * Validates that the code pattern we use to add an appender on
> >> the fly
> >>>>> -     * works with a basic appender that is not the new OutputStream
> >> appender or
> >>>>> -     * new Writer appender.
> >>>>> -     */
> >>>>> -    @Test
> >>>>> -    public void testUpdatePatternWithFileAppender() {
> >>>>> -        final LoggerContext ctx = (LoggerContext)
> >> LogManager.getContext(false);
> >>>>> -        final Configuration config = ctx.getConfiguration();
> >>>>> -        // @formatter:off
> >>>>> -        final Appender appender = FileAppender.newBuilder()
> >>>>> -        .withFileName("target/" + getClass().getName() + ".log")
> >>>>> -
> .withAppend(false).setName("File").setIgnoreExceptions(false)
> >>>>> -            .withBufferedIo(false)
> >>>>> -            .withBufferSize(4000)
> >>>>> -            .setConfiguration(config)
> >>>>> -            .build();
> >>>>> -        // @formatter:on
> >>>>> -        appender.start();
> >>>>> -        config.addAppender(appender);
> >>>>> -        ConfigurationTestUtils.updateLoggers(appender, config);
> >>>>> -        LogManager.getLogger().error("FOO MSG");
> >>>>> -    }
> >>>>> -}
> >>>>> +/*
> >>>>> + * 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.
> >>>>> + */
> >>>>> +package org.apache.logging.log4j.core.appender;
> >>>>> +
> >>>>> +import java.io.BufferedOutputStream;
> >>>>> +import java.io.ByteArrayOutputStream;
> >>>>> +import java.io.OutputStream;
> >>>>> +import java.sql.SQLException;
> >>>>> +
> >>>>> +import org.apache.logging.log4j.LogManager;
> >>>>> +import org.apache.logging.log4j.Logger;
> >>>>> +import org.apache.logging.log4j.core.Appender;
> >>>>> +import org.apache.logging.log4j.core.LoggerContext;
> >>>>> +import org.apache.logging.log4j.core.config.Configuration;
> >>>>> +import org.apache.logging.log4j.core.filter.NoMarkerFilter;
> >>>>> +import org.apache.logging.log4j.core.layout.PatternLayout;
> >>>>> +import org.junit.Assert;
> >>>>> +import org.junit.Rule;
> >>>>> +import org.junit.Test;
> >>>>> +import org.junit.rules.TestName;
> >>>>> +
> >>>>> +/**
> >>>>> + * Tests {@link OutputStreamAppender}.
> >>>>> + */
> >>>>> +public class OutputStreamAppenderTest {
> >>>>> +
> >>>>> +    private static final String TEST_MSG = "FOO ERROR";
> >>>>> +
> >>>>> +    @Rule
> >>>>> +    public TestName testName = new TestName();
> >>>>> +
> >>>>> +    private String getName(final OutputStream out) {
> >>>>> +        return out.getClass().getSimpleName() + "." +
> >> testName.getMethodName();
> >>>>> +    }
> >>>>> +
> >>>>> +    /**
> >>>>> +     * Tests that you can add an output stream appender dynamically.
> >>>>> +     */
> >>>>> +    private void addAppender(final OutputStream outputStream, final
> >> String outputStreamName) {
> >>>>> +        final LoggerContext context =
> LoggerContext.getContext(false);
> >>>>> +        final Configuration config = context.getConfiguration();
> >>>>> +        final PatternLayout layout =
> >> PatternLayout.createDefaultLayout(config);
> >>>>> +        final Appender appender =
> >> OutputStreamAppender.createAppender(layout, null, outputStream,
> >> outputStreamName, false, true);
> >>>>> +        appender.start();
> >>>>> +        config.addAppender(appender);
> >>>>> +        ConfigurationTestUtils.updateLoggers(appender, config);
> >>>>> +    }
> >>>>> +
> >>>>> +    @Test
> >>>>> +    public void testBuildFilter() {
> >>>>> +        final NoMarkerFilter filter =
> >> NoMarkerFilter.newBuilder().build();
> >>>>> +        // @formatter:off
> >>>>> +        final OutputStreamAppender.Builder builder =
> >> OutputStreamAppender.newBuilder()
> >>>>> +                .setName("test")
> >>>>> +                .setFilter(filter);
> >>>>> +        // @formatter:on
> >>>>> +        Assert.assertEquals(filter, builder.getFilter());
> >>>>> +        final OutputStreamAppender appender = builder.build();
> >>>>> +        Assert.assertEquals(filter, appender.getFilter());
> >>>>> +    }
> >>>>> +
> >>>>> +    @Test
> >>>>> +    public void testOutputStreamAppenderToBufferedOutputStream()
> >> throws SQLException {
> >>>>> +        final ByteArrayOutputStream out = new
> ByteArrayOutputStream();
> >>>>> +        final OutputStream os = new BufferedOutputStream(out);
> >>>>> +        final String name = getName(out);
> >>>>> +        final Logger logger = LogManager.getLogger(name);
> >>>>> +        addAppender(os, name);
> >>>>> +        logger.error(TEST_MSG);
> >>>>> +        final String actual = out.toString();
> >>>>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>>>> +    }
> >>>>> +
> >>>>> +    @Test
> >>>>> +    public void testOutputStreamAppenderToByteArrayOutputStream()
> >> throws SQLException {
> >>>>> +        final OutputStream out = new ByteArrayOutputStream();
> >>>>> +        final String name = getName(out);
> >>>>> +        final Logger logger = LogManager.getLogger(name);
> >>>>> +        addAppender(out, name);
> >>>>> +        logger.error(TEST_MSG);
> >>>>> +        final String actual = out.toString();
> >>>>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>>>> +    }
> >>>>> +
> >>>>> +    /**
> >>>>> +     * Validates that the code pattern we use to add an appender on
> >> the fly
> >>>>> +     * works with a basic appender that is not the new OutputStream
> >> appender or
> >>>>> +     * new Writer appender.
> >>>>> +     */
> >>>>> +    @Test
> >>>>> +    public void testUpdatePatternWithFileAppender() {
> >>>>> +        final LoggerContext ctx = (LoggerContext)
> >> LogManager.getContext(false);
> >>>>> +        final Configuration config = ctx.getConfiguration();
> >>>>> +        // @formatter:off
> >>>>> +        final Appender appender = FileAppender.newBuilder()
> >>>>> +        .withFileName("target/" + getClass().getName() + ".log")
> >>>>> +
> .withAppend(false).setName("File").setIgnoreExceptions(false)
> >>>>> +            .withBufferedIo(false)
> >>>>> +            .withBufferSize(4000)
> >>>>> +            .setConfiguration(config)
> >>>>> +            .build();
> >>>>> +        // @formatter:on
> >>>>> +        appender.start();
> >>>>> +        config.addAppender(appender);
> >>>>> +        ConfigurationTestUtils.updateLoggers(appender, config);
> >>>>> +        LogManager.getLogger().error("FOO MSG");
> >>>>> +    }
> >>>>> +}
> >>>>> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
> >>>>> index c3483bd..a9ec160 100644
> >>>>> --- a/src/changes/changes.xml
> >>>>> +++ b/src/changes/changes.xml
> >>>>> @@ -33,6 +33,9 @@
> >>>>>    <action issue="LOG4J2-2639" dev="rgoers" type="add">
> >>>>>      Add builder pattern to Logger interface.
> >>>>>    </action>
> >>>>> +      <action issue="LOG4J2-2673" dev="ggregory" type="fix"
> >> due-to="Yuichi Sugimura, Gary Gregory">
> >>>>> +        OutputStreamAppender.Builder ignores setFilter().
> >>>>> +      </action>
> >>>>>  </release>
> >>>>>  <release version="2.12.1" date="2019-08-06" description="GA Release
> >> 2.12.1">
> >>>>>    <action issue="LOG4J2-1946" dev="rgoers" type="fix" due-to="Igor
> >> Perelyotov">
> >>>>>
> >>>>>
> >>>>
> >>>>
> >>>>
> >>>
> >>>
> >>>
> >>
> >>
> >>
>
>
>

Re: [logging-log4j2] branch release-2.x updated: [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().

Posted by Ralph Goers <ra...@dslextreme.com>.
I believe you have not read this thread. I am not talking about the bug you fixed. I am talking the compatibility breakage you created.

1. The backward compatibility breakage only occurred on the release-2.x branch because revapi is essentially disabled on master. Too much has changed to bother keeping track.
2. I haven’t seen any commit messages indicating you committed anything to fix this.
3. The build is still failing for me.  Try running mvn clean install -DskipTests in log4j-core. It will break for you too.

Please look at the Jenkins build and fix the problems by either reverting the breakage or by adding the recommended changes to revapi.json to document why compatibility was broken.

Ralph


> On Aug 15, 2019, at 4:54 PM, Gary Gregory <ga...@gmail.com> wrote:
> 
> I fixed it already in both branches.
> 
> Gary
> 
> On Thu, Aug 15, 2019, 10:42 Ralph Goers <ra...@dslextreme.com> wrote:
> 
>> Gary,
>> 
>> Are you going to look into this?
>> 
>> Ralph
>> 
>>> On Aug 14, 2019, at 9:17 AM, Ralph Goers <ra...@dslextreme.com>
>> wrote:
>>> 
>>> Any update on this? I’d like my builds to work again.
>>> 
>>> Ralph
>>> 
>>>> On Aug 13, 2019, at 4:29 PM, Ralph Goers <ra...@dslextreme.com>
>> wrote:
>>>> 
>>>> Gary,
>>>> 
>>>> It seems this change broker compatibility. Please see the Jenkins
>> failure. You either need to resolve the code so compatibility is maintained
>> or update revapi.json with the recommended changes.
>>>> 
>>>> Ralph
>>>> 
>>>>> On Aug 13, 2019, at 2:06 PM, ggregory@apache.org wrote:
>>>>> 
>>>>> This is an automated email from the ASF dual-hosted git repository.
>>>>> 
>>>>> ggregory pushed a commit to branch release-2.x
>>>>> in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
>>>>> 
>>>>> 
>>>>> The following commit(s) were added to refs/heads/release-2.x by this
>> push:
>>>>>  new 4679a08  [LOG4J2-2673] OutputStreamAppender.Builder ignores
>> setFilter().
>>>>> 4679a08 is described below
>>>>> 
>>>>> commit 4679a08d4899350f7ee19d050d2a96783b748066
>>>>> Author: Gary Gregory <ga...@gmail.com>
>>>>> AuthorDate: Tue Aug 13 17:06:48 2019 -0400
>>>>> 
>>>>> [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
>>>>> 
>>>>> Also allow a null output stream for convenience instead of an NPE.
>>>>> ---
>>>>> .../log4j/core/appender/OutputStreamAppender.java  | 351
>> +++++++++++----------
>>>>> .../core/appender/OutputStreamAppenderTest.java    | 230 +++++++-------
>>>>> src/changes/changes.xml                            |   3 +
>>>>> 3 files changed, 302 insertions(+), 282 deletions(-)
>>>>> 
>>>>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>>>>> index 7dfd187..dc6f352 100644
>>>>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>>>>> +++
>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>>>>> @@ -1,174 +1,177 @@
>>>>> -/*
>>>>> - * 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.
>>>>> - */
>>>>> -package org.apache.logging.log4j.core.appender;
>>>>> -
>>>>> -import java.io.OutputStream;
>>>>> -import java.io.Serializable;
>>>>> -
>>>>> -import org.apache.logging.log4j.core.Appender;
>>>>> -import org.apache.logging.log4j.core.Core;
>>>>> -import org.apache.logging.log4j.core.Filter;
>>>>> -import org.apache.logging.log4j.core.Layout;
>>>>> -import org.apache.logging.log4j.core.config.Property;
>>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>>> -import
>> org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
>>>>> -import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>>>>> -import org.apache.logging.log4j.core.layout.PatternLayout;
>>>>> -import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
>>>>> -
>>>>> -/**
>>>>> - * Appends log events to a given output stream using a layout.
>>>>> - * <p>
>>>>> - * Character encoding is handled within the Layout.
>>>>> - * </p>
>>>>> - */
>>>>> -@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME,
>> elementType = Appender.ELEMENT_TYPE, printObject = true)
>>>>> -public final class OutputStreamAppender extends
>> AbstractOutputStreamAppender<OutputStreamManager> {
>>>>> -
>>>>> -    /**
>>>>> -     * Builds OutputStreamAppender instances.
>>>>> -     */
>>>>> -    public static class Builder<B extends Builder<B>> extends
>> AbstractOutputStreamAppender.Builder<B>
>>>>> -            implements
>> org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
>>>>> -
>>>>> -        private Filter filter;
>>>>> -
>>>>> -        private boolean follow = false;
>>>>> -
>>>>> -        private final boolean ignoreExceptions = true;
>>>>> -
>>>>> -        private OutputStream target;
>>>>> -
>>>>> -        @Override
>>>>> -        public OutputStreamAppender build() {
>>>>> -            final Layout<? extends Serializable> layout = getLayout();
>>>>> -            final Layout<? extends Serializable> actualLayout =
>> layout == null ? PatternLayout.createDefaultLayout()
>>>>> -                    : layout;
>>>>> -            return new OutputStreamAppender(getName(), actualLayout,
>> filter, getManager(target, follow, actualLayout),
>>>>> -                    ignoreExceptions, getPropertyArray());
>>>>> -        }
>>>>> -
>>>>> -        public B setFollow(final boolean shouldFollow) {
>>>>> -            this.follow = shouldFollow;
>>>>> -            return asBuilder();
>>>>> -        }
>>>>> -
>>>>> -        public B setTarget(final OutputStream aTarget) {
>>>>> -            this.target = aTarget;
>>>>> -            return asBuilder();
>>>>> -        }
>>>>> -    }
>>>>> -
>>>>> -    /**
>>>>> -     * Holds data to pass to factory method.
>>>>> -     */
>>>>> -    private static class FactoryData {
>>>>> -        private final Layout<? extends Serializable> layout;
>>>>> -        private final String name;
>>>>> -        private final OutputStream os;
>>>>> -
>>>>> -        /**
>>>>> -         * Builds instances.
>>>>> -         *
>>>>> -         * @param os
>>>>> -         *            The OutputStream.
>>>>> -         * @param type
>>>>> -         *            The name of the target.
>>>>> -         * @param layout
>>>>> -         *            A Serializable layout
>>>>> -         */
>>>>> -        public FactoryData(final OutputStream os, final String type,
>> final Layout<? extends Serializable> layout) {
>>>>> -            this.os = os;
>>>>> -            this.name = type;
>>>>> -            this.layout = layout;
>>>>> -        }
>>>>> -    }
>>>>> -
>>>>> -    /**
>>>>> -     * Creates the manager.
>>>>> -     */
>>>>> -    private static class OutputStreamManagerFactory implements
>> ManagerFactory<OutputStreamManager, FactoryData> {
>>>>> -
>>>>> -        /**
>>>>> -         * Creates an OutputStreamManager.
>>>>> -         *
>>>>> -         * @param name
>>>>> -         *            The name of the entity to manage.
>>>>> -         * @param data
>>>>> -         *            The data required to create the entity.
>>>>> -         * @return The OutputStreamManager
>>>>> -         */
>>>>> -        @Override
>>>>> -        public OutputStreamManager createManager(final String name,
>> final FactoryData data) {
>>>>> -            return new OutputStreamManager(data.os, data.name,
>> data.layout, true);
>>>>> -        }
>>>>> -    }
>>>>> -
>>>>> -    private static OutputStreamManagerFactory factory = new
>> OutputStreamManagerFactory();
>>>>> -
>>>>> -    /**
>>>>> -     * Creates an OutputStream Appender.
>>>>> -     *
>>>>> -     * @param layout
>>>>> -     *            The layout to use or null to get the default layout.
>>>>> -     * @param filter
>>>>> -     *            The Filter or null.
>>>>> -     * @param target
>>>>> -     *            an output stream.
>>>>> -     * @param follow
>>>>> -     *            If true will follow changes to the underlying
>> output stream.
>>>>> -     *            Use false as the default.
>>>>> -     * @param name
>>>>> -     *            The name of the Appender (required).
>>>>> -     * @param ignore
>>>>> -     *            If {@code "true"} (default) exceptions encountered
>> when
>>>>> -     *            appending events are logged; otherwise they are
>> propagated to
>>>>> -     *            the caller. Use true as the default.
>>>>> -     * @return The ConsoleAppender.
>>>>> -     */
>>>>> -    @PluginFactory
>>>>> -    public static OutputStreamAppender createAppender(Layout<?
>> extends Serializable> layout, final Filter filter,
>>>>> -            final OutputStream target, final String name, final
>> boolean follow, final boolean ignore) {
>>>>> -        if (name == null) {
>>>>> -            LOGGER.error("No name provided for OutputStreamAppender");
>>>>> -            return null;
>>>>> -        }
>>>>> -        if (layout == null) {
>>>>> -            layout = PatternLayout.createDefaultLayout();
>>>>> -        }
>>>>> -        return new OutputStreamAppender(name, layout, filter,
>> getManager(target, follow, layout), ignore, null);
>>>>> -    }
>>>>> -
>>>>> -    private static OutputStreamManager getManager(final OutputStream
>> target, final boolean follow,
>>>>> -            final Layout<? extends Serializable> layout) {
>>>>> -        final OutputStream os = new CloseShieldOutputStream(target);
>>>>> -        final String managerName = target.getClass().getName() + "@"
>> + Integer.toHexString(target.hashCode()) + '.'
>>>>> -                + follow;
>>>>> -        return OutputStreamManager.getManager(managerName, new
>> FactoryData(os, managerName, layout), factory);
>>>>> -    }
>>>>> -
>>>>> -    @PluginBuilderFactory
>>>>> -    public static Builder newBuilder() {
>>>>> -        return new Builder();
>>>>> -    }
>>>>> -
>>>>> -    private OutputStreamAppender(final String name, final Layout<?
>> extends Serializable> layout, final Filter filter,
>>>>> -            final OutputStreamManager manager, final boolean
>> ignoreExceptions, final Property[] properties) {
>>>>> -        super(name, layout, filter, ignoreExceptions, true,
>> properties, manager);
>>>>> -    }
>>>>> -
>>>>> -}
>>>>> +/*
>>>>> + * 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.
>>>>> + */
>>>>> +package org.apache.logging.log4j.core.appender;
>>>>> +
>>>>> +import java.io.OutputStream;
>>>>> +import java.io.Serializable;
>>>>> +
>>>>> +import org.apache.logging.log4j.core.Appender;
>>>>> +import org.apache.logging.log4j.core.Core;
>>>>> +import org.apache.logging.log4j.core.Filter;
>>>>> +import org.apache.logging.log4j.core.Layout;
>>>>> +import org.apache.logging.log4j.core.config.Property;
>>>>> +import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>>> +import
>> org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
>>>>> +import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>>>>> +import org.apache.logging.log4j.core.layout.PatternLayout;
>>>>> +import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
>>>>> +import org.apache.logging.log4j.core.util.NullOutputStream;
>>>>> +
>>>>> +/**
>>>>> + * Appends log events to a given output stream using a layout.
>>>>> + * <p>
>>>>> + * Character encoding is handled within the Layout.
>>>>> + * </p>
>>>>> + */
>>>>> +@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME,
>> elementType = Appender.ELEMENT_TYPE, printObject = true)
>>>>> +public final class OutputStreamAppender extends
>> AbstractOutputStreamAppender<OutputStreamManager> {
>>>>> +
>>>>> +    /**
>>>>> +     * Builds OutputStreamAppender instances.
>>>>> +     *
>>>>> +     * @param <B>
>>>>> +     *            The type to build.
>>>>> +     */
>>>>> +    public static class Builder<B extends Builder<B>> extends
>> AbstractOutputStreamAppender.Builder<B>
>>>>> +            implements
>> org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
>>>>> +
>>>>> +        private boolean follow = false;
>>>>> +
>>>>> +        private final boolean ignoreExceptions = true;
>>>>> +
>>>>> +        private OutputStream target;
>>>>> +
>>>>> +        @Override
>>>>> +        public OutputStreamAppender build() {
>>>>> +            final Layout<? extends Serializable> layout = getLayout();
>>>>> +            final Layout<? extends Serializable> actualLayout =
>> layout == null ? PatternLayout.createDefaultLayout()
>>>>> +                    : layout;
>>>>> +            return new OutputStreamAppender(getName(), actualLayout,
>> getFilter(), getManager(target, follow, actualLayout),
>>>>> +                    ignoreExceptions, getPropertyArray());
>>>>> +        }
>>>>> +
>>>>> +        public B setFollow(final boolean shouldFollow) {
>>>>> +            this.follow = shouldFollow;
>>>>> +            return asBuilder();
>>>>> +        }
>>>>> +
>>>>> +        public B setTarget(final OutputStream aTarget) {
>>>>> +            this.target = aTarget;
>>>>> +            return asBuilder();
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Holds data to pass to factory method.
>>>>> +     */
>>>>> +    private static class FactoryData {
>>>>> +        private final Layout<? extends Serializable> layout;
>>>>> +        private final String name;
>>>>> +        private final OutputStream os;
>>>>> +
>>>>> +        /**
>>>>> +         * Builds instances.
>>>>> +         *
>>>>> +         * @param os
>>>>> +         *            The OutputStream.
>>>>> +         * @param type
>>>>> +         *            The name of the target.
>>>>> +         * @param layout
>>>>> +         *            A Serializable layout
>>>>> +         */
>>>>> +        public FactoryData(final OutputStream os, final String type,
>> final Layout<? extends Serializable> layout) {
>>>>> +            this.os = os;
>>>>> +            this.name = type;
>>>>> +            this.layout = layout;
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Creates the manager.
>>>>> +     */
>>>>> +    private static class OutputStreamManagerFactory implements
>> ManagerFactory<OutputStreamManager, FactoryData> {
>>>>> +
>>>>> +        /**
>>>>> +         * Creates an OutputStreamManager.
>>>>> +         *
>>>>> +         * @param name
>>>>> +         *            The name of the entity to manage.
>>>>> +         * @param data
>>>>> +         *            The data required to create the entity.
>>>>> +         * @return The OutputStreamManager
>>>>> +         */
>>>>> +        @Override
>>>>> +        public OutputStreamManager createManager(final String name,
>> final FactoryData data) {
>>>>> +            return new OutputStreamManager(data.os, data.name,
>> data.layout, true);
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +    private static OutputStreamManagerFactory factory = new
>> OutputStreamManagerFactory();
>>>>> +
>>>>> +    /**
>>>>> +     * Creates an OutputStream Appender.
>>>>> +     *
>>>>> +     * @param layout
>>>>> +     *            The layout to use or null to get the default layout.
>>>>> +     * @param filter
>>>>> +     *            The Filter or null.
>>>>> +     * @param target
>>>>> +     *            an output stream.
>>>>> +     * @param follow
>>>>> +     *            If true will follow changes to the underlying
>> output stream.
>>>>> +     *            Use false as the default.
>>>>> +     * @param name
>>>>> +     *            The name of the Appender (required).
>>>>> +     * @param ignore
>>>>> +     *            If {@code "true"} (default) exceptions encountered
>> when
>>>>> +     *            appending events are logged; otherwise they are
>> propagated to
>>>>> +     *            the caller. Use true as the default.
>>>>> +     * @return The ConsoleAppender.
>>>>> +     */
>>>>> +    @PluginFactory
>>>>> +    public static OutputStreamAppender createAppender(Layout<?
>> extends Serializable> layout, final Filter filter,
>>>>> +            final OutputStream target, final String name, final
>> boolean follow, final boolean ignore) {
>>>>> +        if (name == null) {
>>>>> +            LOGGER.error("No name provided for OutputStreamAppender");
>>>>> +            return null;
>>>>> +        }
>>>>> +        if (layout == null) {
>>>>> +            layout = PatternLayout.createDefaultLayout();
>>>>> +        }
>>>>> +        return new OutputStreamAppender(name, layout, filter,
>> getManager(target, follow, layout), ignore, null);
>>>>> +    }
>>>>> +
>>>>> +    private static OutputStreamManager getManager(final OutputStream
>> target, final boolean follow,
>>>>> +            final Layout<? extends Serializable> layout) {
>>>>> +        final OutputStream os = target == null ?
>> NullOutputStream.getInstance() : new CloseShieldOutputStream(target);
>>>>> +        final OutputStream targetRef = target == null ? os : target;
>>>>> +        final String managerName = targetRef.getClass().getName() +
>> "@" + Integer.toHexString(targetRef.hashCode())
>>>>> +                + '.' + follow;
>>>>> +        return OutputStreamManager.getManager(managerName, new
>> FactoryData(os, managerName, layout), factory);
>>>>> +    }
>>>>> +
>>>>> +    @PluginBuilderFactory
>>>>> +    public static <B extends Builder<B>> B newBuilder() {
>>>>> +        return new Builder<B>().asBuilder();
>>>>> +    }
>>>>> +
>>>>> +    private OutputStreamAppender(final String name, final Layout<?
>> extends Serializable> layout, final Filter filter,
>>>>> +            final OutputStreamManager manager, final boolean
>> ignoreExceptions, final Property[] properties) {
>>>>> +        super(name, layout, filter, ignoreExceptions, true,
>> properties, manager);
>>>>> +    }
>>>>> +
>>>>> +}
>>>>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>> b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>>>>> index 00af014..c1448bf 100644
>>>>> ---
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>>>>> +++
>> b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>>>>> @@ -1,108 +1,122 @@
>>>>> -/*
>>>>> - * 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.
>>>>> - */
>>>>> -package org.apache.logging.log4j.core.appender;
>>>>> -
>>>>> -import java.io.BufferedOutputStream;
>>>>> -import java.io.ByteArrayOutputStream;
>>>>> -import java.io.OutputStream;
>>>>> -import java.sql.SQLException;
>>>>> -
>>>>> -import org.apache.logging.log4j.LogManager;
>>>>> -import org.apache.logging.log4j.Logger;
>>>>> -import org.apache.logging.log4j.core.Appender;
>>>>> -import org.apache.logging.log4j.core.LoggerContext;
>>>>> -import org.apache.logging.log4j.core.config.Configuration;
>>>>> -import org.apache.logging.log4j.core.layout.PatternLayout;
>>>>> -import org.junit.Assert;
>>>>> -import org.junit.Rule;
>>>>> -import org.junit.Test;
>>>>> -import org.junit.rules.TestName;
>>>>> -
>>>>> -/**
>>>>> - * Tests {@link OutputStreamAppender}.
>>>>> - */
>>>>> -public class OutputStreamAppenderTest {
>>>>> -
>>>>> -    private static final String TEST_MSG = "FOO ERROR";
>>>>> -
>>>>> -    @Rule
>>>>> -    public TestName testName = new TestName();
>>>>> -
>>>>> -    private String getName(final OutputStream out) {
>>>>> -        return out.getClass().getSimpleName() + "." +
>> testName.getMethodName();
>>>>> -    }
>>>>> -
>>>>> -    /**
>>>>> -     * Tests that you can add an output stream appender dynamically.
>>>>> -     */
>>>>> -    private void addAppender(final OutputStream outputStream, final
>> String outputStreamName) {
>>>>> -        final LoggerContext context = LoggerContext.getContext(false);
>>>>> -        final Configuration config = context.getConfiguration();
>>>>> -        final PatternLayout layout =
>> PatternLayout.createDefaultLayout(config);
>>>>> -        final Appender appender =
>> OutputStreamAppender.createAppender(layout, null, outputStream,
>> outputStreamName, false, true);
>>>>> -        appender.start();
>>>>> -        config.addAppender(appender);
>>>>> -        ConfigurationTestUtils.updateLoggers(appender, config);
>>>>> -    }
>>>>> -
>>>>> -    @Test
>>>>> -    public void testOutputStreamAppenderToBufferedOutputStream()
>> throws SQLException {
>>>>> -        final ByteArrayOutputStream out = new ByteArrayOutputStream();
>>>>> -        final OutputStream os = new BufferedOutputStream(out);
>>>>> -        final String name = getName(out);
>>>>> -        final Logger logger = LogManager.getLogger(name);
>>>>> -        addAppender(os, name);
>>>>> -        logger.error(TEST_MSG);
>>>>> -        final String actual = out.toString();
>>>>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>>>>> -    }
>>>>> -
>>>>> -    @Test
>>>>> -    public void testOutputStreamAppenderToByteArrayOutputStream()
>> throws SQLException {
>>>>> -        final OutputStream out = new ByteArrayOutputStream();
>>>>> -        final String name = getName(out);
>>>>> -        final Logger logger = LogManager.getLogger(name);
>>>>> -        addAppender(out, name);
>>>>> -        logger.error(TEST_MSG);
>>>>> -        final String actual = out.toString();
>>>>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>>>>> -    }
>>>>> -
>>>>> -    /**
>>>>> -     * Validates that the code pattern we use to add an appender on
>> the fly
>>>>> -     * works with a basic appender that is not the new OutputStream
>> appender or
>>>>> -     * new Writer appender.
>>>>> -     */
>>>>> -    @Test
>>>>> -    public void testUpdatePatternWithFileAppender() {
>>>>> -        final LoggerContext ctx = (LoggerContext)
>> LogManager.getContext(false);
>>>>> -        final Configuration config = ctx.getConfiguration();
>>>>> -        // @formatter:off
>>>>> -        final Appender appender = FileAppender.newBuilder()
>>>>> -        .withFileName("target/" + getClass().getName() + ".log")
>>>>> -        .withAppend(false).setName("File").setIgnoreExceptions(false)
>>>>> -            .withBufferedIo(false)
>>>>> -            .withBufferSize(4000)
>>>>> -            .setConfiguration(config)
>>>>> -            .build();
>>>>> -        // @formatter:on
>>>>> -        appender.start();
>>>>> -        config.addAppender(appender);
>>>>> -        ConfigurationTestUtils.updateLoggers(appender, config);
>>>>> -        LogManager.getLogger().error("FOO MSG");
>>>>> -    }
>>>>> -}
>>>>> +/*
>>>>> + * 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.
>>>>> + */
>>>>> +package org.apache.logging.log4j.core.appender;
>>>>> +
>>>>> +import java.io.BufferedOutputStream;
>>>>> +import java.io.ByteArrayOutputStream;
>>>>> +import java.io.OutputStream;
>>>>> +import java.sql.SQLException;
>>>>> +
>>>>> +import org.apache.logging.log4j.LogManager;
>>>>> +import org.apache.logging.log4j.Logger;
>>>>> +import org.apache.logging.log4j.core.Appender;
>>>>> +import org.apache.logging.log4j.core.LoggerContext;
>>>>> +import org.apache.logging.log4j.core.config.Configuration;
>>>>> +import org.apache.logging.log4j.core.filter.NoMarkerFilter;
>>>>> +import org.apache.logging.log4j.core.layout.PatternLayout;
>>>>> +import org.junit.Assert;
>>>>> +import org.junit.Rule;
>>>>> +import org.junit.Test;
>>>>> +import org.junit.rules.TestName;
>>>>> +
>>>>> +/**
>>>>> + * Tests {@link OutputStreamAppender}.
>>>>> + */
>>>>> +public class OutputStreamAppenderTest {
>>>>> +
>>>>> +    private static final String TEST_MSG = "FOO ERROR";
>>>>> +
>>>>> +    @Rule
>>>>> +    public TestName testName = new TestName();
>>>>> +
>>>>> +    private String getName(final OutputStream out) {
>>>>> +        return out.getClass().getSimpleName() + "." +
>> testName.getMethodName();
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Tests that you can add an output stream appender dynamically.
>>>>> +     */
>>>>> +    private void addAppender(final OutputStream outputStream, final
>> String outputStreamName) {
>>>>> +        final LoggerContext context = LoggerContext.getContext(false);
>>>>> +        final Configuration config = context.getConfiguration();
>>>>> +        final PatternLayout layout =
>> PatternLayout.createDefaultLayout(config);
>>>>> +        final Appender appender =
>> OutputStreamAppender.createAppender(layout, null, outputStream,
>> outputStreamName, false, true);
>>>>> +        appender.start();
>>>>> +        config.addAppender(appender);
>>>>> +        ConfigurationTestUtils.updateLoggers(appender, config);
>>>>> +    }
>>>>> +
>>>>> +    @Test
>>>>> +    public void testBuildFilter() {
>>>>> +        final NoMarkerFilter filter =
>> NoMarkerFilter.newBuilder().build();
>>>>> +        // @formatter:off
>>>>> +        final OutputStreamAppender.Builder builder =
>> OutputStreamAppender.newBuilder()
>>>>> +                .setName("test")
>>>>> +                .setFilter(filter);
>>>>> +        // @formatter:on
>>>>> +        Assert.assertEquals(filter, builder.getFilter());
>>>>> +        final OutputStreamAppender appender = builder.build();
>>>>> +        Assert.assertEquals(filter, appender.getFilter());
>>>>> +    }
>>>>> +
>>>>> +    @Test
>>>>> +    public void testOutputStreamAppenderToBufferedOutputStream()
>> throws SQLException {
>>>>> +        final ByteArrayOutputStream out = new ByteArrayOutputStream();
>>>>> +        final OutputStream os = new BufferedOutputStream(out);
>>>>> +        final String name = getName(out);
>>>>> +        final Logger logger = LogManager.getLogger(name);
>>>>> +        addAppender(os, name);
>>>>> +        logger.error(TEST_MSG);
>>>>> +        final String actual = out.toString();
>>>>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>>>>> +    }
>>>>> +
>>>>> +    @Test
>>>>> +    public void testOutputStreamAppenderToByteArrayOutputStream()
>> throws SQLException {
>>>>> +        final OutputStream out = new ByteArrayOutputStream();
>>>>> +        final String name = getName(out);
>>>>> +        final Logger logger = LogManager.getLogger(name);
>>>>> +        addAppender(out, name);
>>>>> +        logger.error(TEST_MSG);
>>>>> +        final String actual = out.toString();
>>>>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>>>>> +    }
>>>>> +
>>>>> +    /**
>>>>> +     * Validates that the code pattern we use to add an appender on
>> the fly
>>>>> +     * works with a basic appender that is not the new OutputStream
>> appender or
>>>>> +     * new Writer appender.
>>>>> +     */
>>>>> +    @Test
>>>>> +    public void testUpdatePatternWithFileAppender() {
>>>>> +        final LoggerContext ctx = (LoggerContext)
>> LogManager.getContext(false);
>>>>> +        final Configuration config = ctx.getConfiguration();
>>>>> +        // @formatter:off
>>>>> +        final Appender appender = FileAppender.newBuilder()
>>>>> +        .withFileName("target/" + getClass().getName() + ".log")
>>>>> +        .withAppend(false).setName("File").setIgnoreExceptions(false)
>>>>> +            .withBufferedIo(false)
>>>>> +            .withBufferSize(4000)
>>>>> +            .setConfiguration(config)
>>>>> +            .build();
>>>>> +        // @formatter:on
>>>>> +        appender.start();
>>>>> +        config.addAppender(appender);
>>>>> +        ConfigurationTestUtils.updateLoggers(appender, config);
>>>>> +        LogManager.getLogger().error("FOO MSG");
>>>>> +    }
>>>>> +}
>>>>> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
>>>>> index c3483bd..a9ec160 100644
>>>>> --- a/src/changes/changes.xml
>>>>> +++ b/src/changes/changes.xml
>>>>> @@ -33,6 +33,9 @@
>>>>>    <action issue="LOG4J2-2639" dev="rgoers" type="add">
>>>>>      Add builder pattern to Logger interface.
>>>>>    </action>
>>>>> +      <action issue="LOG4J2-2673" dev="ggregory" type="fix"
>> due-to="Yuichi Sugimura, Gary Gregory">
>>>>> +        OutputStreamAppender.Builder ignores setFilter().
>>>>> +      </action>
>>>>>  </release>
>>>>>  <release version="2.12.1" date="2019-08-06" description="GA Release
>> 2.12.1">
>>>>>    <action issue="LOG4J2-1946" dev="rgoers" type="fix" due-to="Igor
>> Perelyotov">
>>>>> 
>>>>> 
>>>> 
>>>> 
>>>> 
>>> 
>>> 
>>> 
>> 
>> 
>> 



Re: [logging-log4j2] branch release-2.x updated: [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().

Posted by Gary Gregory <ga...@gmail.com>.
I fixed it already in both branches.

Gary

On Thu, Aug 15, 2019, 10:42 Ralph Goers <ra...@dslextreme.com> wrote:

> Gary,
>
> Are you going to look into this?
>
> Ralph
>
> > On Aug 14, 2019, at 9:17 AM, Ralph Goers <ra...@dslextreme.com>
> wrote:
> >
> > Any update on this? I’d like my builds to work again.
> >
> > Ralph
> >
> >> On Aug 13, 2019, at 4:29 PM, Ralph Goers <ra...@dslextreme.com>
> wrote:
> >>
> >> Gary,
> >>
> >> It seems this change broker compatibility. Please see the Jenkins
> failure. You either need to resolve the code so compatibility is maintained
> or update revapi.json with the recommended changes.
> >>
> >> Ralph
> >>
> >>> On Aug 13, 2019, at 2:06 PM, ggregory@apache.org wrote:
> >>>
> >>> This is an automated email from the ASF dual-hosted git repository.
> >>>
> >>> ggregory pushed a commit to branch release-2.x
> >>> in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
> >>>
> >>>
> >>> The following commit(s) were added to refs/heads/release-2.x by this
> push:
> >>>   new 4679a08  [LOG4J2-2673] OutputStreamAppender.Builder ignores
> setFilter().
> >>> 4679a08 is described below
> >>>
> >>> commit 4679a08d4899350f7ee19d050d2a96783b748066
> >>> Author: Gary Gregory <ga...@gmail.com>
> >>> AuthorDate: Tue Aug 13 17:06:48 2019 -0400
> >>>
> >>>  [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
> >>>
> >>>  Also allow a null output stream for convenience instead of an NPE.
> >>> ---
> >>> .../log4j/core/appender/OutputStreamAppender.java  | 351
> +++++++++++----------
> >>> .../core/appender/OutputStreamAppenderTest.java    | 230 +++++++-------
> >>> src/changes/changes.xml                            |   3 +
> >>> 3 files changed, 302 insertions(+), 282 deletions(-)
> >>>
> >>> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>> index 7dfd187..dc6f352 100644
> >>> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>> +++
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> >>> @@ -1,174 +1,177 @@
> >>> -/*
> >>> - * 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.
> >>> - */
> >>> -package org.apache.logging.log4j.core.appender;
> >>> -
> >>> -import java.io.OutputStream;
> >>> -import java.io.Serializable;
> >>> -
> >>> -import org.apache.logging.log4j.core.Appender;
> >>> -import org.apache.logging.log4j.core.Core;
> >>> -import org.apache.logging.log4j.core.Filter;
> >>> -import org.apache.logging.log4j.core.Layout;
> >>> -import org.apache.logging.log4j.core.config.Property;
> >>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> >>> -import
> org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
> >>> -import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> >>> -import org.apache.logging.log4j.core.layout.PatternLayout;
> >>> -import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
> >>> -
> >>> -/**
> >>> - * Appends log events to a given output stream using a layout.
> >>> - * <p>
> >>> - * Character encoding is handled within the Layout.
> >>> - * </p>
> >>> - */
> >>> -@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME,
> elementType = Appender.ELEMENT_TYPE, printObject = true)
> >>> -public final class OutputStreamAppender extends
> AbstractOutputStreamAppender<OutputStreamManager> {
> >>> -
> >>> -    /**
> >>> -     * Builds OutputStreamAppender instances.
> >>> -     */
> >>> -    public static class Builder<B extends Builder<B>> extends
> AbstractOutputStreamAppender.Builder<B>
> >>> -            implements
> org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
> >>> -
> >>> -        private Filter filter;
> >>> -
> >>> -        private boolean follow = false;
> >>> -
> >>> -        private final boolean ignoreExceptions = true;
> >>> -
> >>> -        private OutputStream target;
> >>> -
> >>> -        @Override
> >>> -        public OutputStreamAppender build() {
> >>> -            final Layout<? extends Serializable> layout = getLayout();
> >>> -            final Layout<? extends Serializable> actualLayout =
> layout == null ? PatternLayout.createDefaultLayout()
> >>> -                    : layout;
> >>> -            return new OutputStreamAppender(getName(), actualLayout,
> filter, getManager(target, follow, actualLayout),
> >>> -                    ignoreExceptions, getPropertyArray());
> >>> -        }
> >>> -
> >>> -        public B setFollow(final boolean shouldFollow) {
> >>> -            this.follow = shouldFollow;
> >>> -            return asBuilder();
> >>> -        }
> >>> -
> >>> -        public B setTarget(final OutputStream aTarget) {
> >>> -            this.target = aTarget;
> >>> -            return asBuilder();
> >>> -        }
> >>> -    }
> >>> -
> >>> -    /**
> >>> -     * Holds data to pass to factory method.
> >>> -     */
> >>> -    private static class FactoryData {
> >>> -        private final Layout<? extends Serializable> layout;
> >>> -        private final String name;
> >>> -        private final OutputStream os;
> >>> -
> >>> -        /**
> >>> -         * Builds instances.
> >>> -         *
> >>> -         * @param os
> >>> -         *            The OutputStream.
> >>> -         * @param type
> >>> -         *            The name of the target.
> >>> -         * @param layout
> >>> -         *            A Serializable layout
> >>> -         */
> >>> -        public FactoryData(final OutputStream os, final String type,
> final Layout<? extends Serializable> layout) {
> >>> -            this.os = os;
> >>> -            this.name = type;
> >>> -            this.layout = layout;
> >>> -        }
> >>> -    }
> >>> -
> >>> -    /**
> >>> -     * Creates the manager.
> >>> -     */
> >>> -    private static class OutputStreamManagerFactory implements
> ManagerFactory<OutputStreamManager, FactoryData> {
> >>> -
> >>> -        /**
> >>> -         * Creates an OutputStreamManager.
> >>> -         *
> >>> -         * @param name
> >>> -         *            The name of the entity to manage.
> >>> -         * @param data
> >>> -         *            The data required to create the entity.
> >>> -         * @return The OutputStreamManager
> >>> -         */
> >>> -        @Override
> >>> -        public OutputStreamManager createManager(final String name,
> final FactoryData data) {
> >>> -            return new OutputStreamManager(data.os, data.name,
> data.layout, true);
> >>> -        }
> >>> -    }
> >>> -
> >>> -    private static OutputStreamManagerFactory factory = new
> OutputStreamManagerFactory();
> >>> -
> >>> -    /**
> >>> -     * Creates an OutputStream Appender.
> >>> -     *
> >>> -     * @param layout
> >>> -     *            The layout to use or null to get the default layout.
> >>> -     * @param filter
> >>> -     *            The Filter or null.
> >>> -     * @param target
> >>> -     *            an output stream.
> >>> -     * @param follow
> >>> -     *            If true will follow changes to the underlying
> output stream.
> >>> -     *            Use false as the default.
> >>> -     * @param name
> >>> -     *            The name of the Appender (required).
> >>> -     * @param ignore
> >>> -     *            If {@code "true"} (default) exceptions encountered
> when
> >>> -     *            appending events are logged; otherwise they are
> propagated to
> >>> -     *            the caller. Use true as the default.
> >>> -     * @return The ConsoleAppender.
> >>> -     */
> >>> -    @PluginFactory
> >>> -    public static OutputStreamAppender createAppender(Layout<?
> extends Serializable> layout, final Filter filter,
> >>> -            final OutputStream target, final String name, final
> boolean follow, final boolean ignore) {
> >>> -        if (name == null) {
> >>> -            LOGGER.error("No name provided for OutputStreamAppender");
> >>> -            return null;
> >>> -        }
> >>> -        if (layout == null) {
> >>> -            layout = PatternLayout.createDefaultLayout();
> >>> -        }
> >>> -        return new OutputStreamAppender(name, layout, filter,
> getManager(target, follow, layout), ignore, null);
> >>> -    }
> >>> -
> >>> -    private static OutputStreamManager getManager(final OutputStream
> target, final boolean follow,
> >>> -            final Layout<? extends Serializable> layout) {
> >>> -        final OutputStream os = new CloseShieldOutputStream(target);
> >>> -        final String managerName = target.getClass().getName() + "@"
> + Integer.toHexString(target.hashCode()) + '.'
> >>> -                + follow;
> >>> -        return OutputStreamManager.getManager(managerName, new
> FactoryData(os, managerName, layout), factory);
> >>> -    }
> >>> -
> >>> -    @PluginBuilderFactory
> >>> -    public static Builder newBuilder() {
> >>> -        return new Builder();
> >>> -    }
> >>> -
> >>> -    private OutputStreamAppender(final String name, final Layout<?
> extends Serializable> layout, final Filter filter,
> >>> -            final OutputStreamManager manager, final boolean
> ignoreExceptions, final Property[] properties) {
> >>> -        super(name, layout, filter, ignoreExceptions, true,
> properties, manager);
> >>> -    }
> >>> -
> >>> -}
> >>> +/*
> >>> + * 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.
> >>> + */
> >>> +package org.apache.logging.log4j.core.appender;
> >>> +
> >>> +import java.io.OutputStream;
> >>> +import java.io.Serializable;
> >>> +
> >>> +import org.apache.logging.log4j.core.Appender;
> >>> +import org.apache.logging.log4j.core.Core;
> >>> +import org.apache.logging.log4j.core.Filter;
> >>> +import org.apache.logging.log4j.core.Layout;
> >>> +import org.apache.logging.log4j.core.config.Property;
> >>> +import org.apache.logging.log4j.core.config.plugins.Plugin;
> >>> +import
> org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
> >>> +import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> >>> +import org.apache.logging.log4j.core.layout.PatternLayout;
> >>> +import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
> >>> +import org.apache.logging.log4j.core.util.NullOutputStream;
> >>> +
> >>> +/**
> >>> + * Appends log events to a given output stream using a layout.
> >>> + * <p>
> >>> + * Character encoding is handled within the Layout.
> >>> + * </p>
> >>> + */
> >>> +@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME,
> elementType = Appender.ELEMENT_TYPE, printObject = true)
> >>> +public final class OutputStreamAppender extends
> AbstractOutputStreamAppender<OutputStreamManager> {
> >>> +
> >>> +    /**
> >>> +     * Builds OutputStreamAppender instances.
> >>> +     *
> >>> +     * @param <B>
> >>> +     *            The type to build.
> >>> +     */
> >>> +    public static class Builder<B extends Builder<B>> extends
> AbstractOutputStreamAppender.Builder<B>
> >>> +            implements
> org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
> >>> +
> >>> +        private boolean follow = false;
> >>> +
> >>> +        private final boolean ignoreExceptions = true;
> >>> +
> >>> +        private OutputStream target;
> >>> +
> >>> +        @Override
> >>> +        public OutputStreamAppender build() {
> >>> +            final Layout<? extends Serializable> layout = getLayout();
> >>> +            final Layout<? extends Serializable> actualLayout =
> layout == null ? PatternLayout.createDefaultLayout()
> >>> +                    : layout;
> >>> +            return new OutputStreamAppender(getName(), actualLayout,
> getFilter(), getManager(target, follow, actualLayout),
> >>> +                    ignoreExceptions, getPropertyArray());
> >>> +        }
> >>> +
> >>> +        public B setFollow(final boolean shouldFollow) {
> >>> +            this.follow = shouldFollow;
> >>> +            return asBuilder();
> >>> +        }
> >>> +
> >>> +        public B setTarget(final OutputStream aTarget) {
> >>> +            this.target = aTarget;
> >>> +            return asBuilder();
> >>> +        }
> >>> +    }
> >>> +
> >>> +    /**
> >>> +     * Holds data to pass to factory method.
> >>> +     */
> >>> +    private static class FactoryData {
> >>> +        private final Layout<? extends Serializable> layout;
> >>> +        private final String name;
> >>> +        private final OutputStream os;
> >>> +
> >>> +        /**
> >>> +         * Builds instances.
> >>> +         *
> >>> +         * @param os
> >>> +         *            The OutputStream.
> >>> +         * @param type
> >>> +         *            The name of the target.
> >>> +         * @param layout
> >>> +         *            A Serializable layout
> >>> +         */
> >>> +        public FactoryData(final OutputStream os, final String type,
> final Layout<? extends Serializable> layout) {
> >>> +            this.os = os;
> >>> +            this.name = type;
> >>> +            this.layout = layout;
> >>> +        }
> >>> +    }
> >>> +
> >>> +    /**
> >>> +     * Creates the manager.
> >>> +     */
> >>> +    private static class OutputStreamManagerFactory implements
> ManagerFactory<OutputStreamManager, FactoryData> {
> >>> +
> >>> +        /**
> >>> +         * Creates an OutputStreamManager.
> >>> +         *
> >>> +         * @param name
> >>> +         *            The name of the entity to manage.
> >>> +         * @param data
> >>> +         *            The data required to create the entity.
> >>> +         * @return The OutputStreamManager
> >>> +         */
> >>> +        @Override
> >>> +        public OutputStreamManager createManager(final String name,
> final FactoryData data) {
> >>> +            return new OutputStreamManager(data.os, data.name,
> data.layout, true);
> >>> +        }
> >>> +    }
> >>> +
> >>> +    private static OutputStreamManagerFactory factory = new
> OutputStreamManagerFactory();
> >>> +
> >>> +    /**
> >>> +     * Creates an OutputStream Appender.
> >>> +     *
> >>> +     * @param layout
> >>> +     *            The layout to use or null to get the default layout.
> >>> +     * @param filter
> >>> +     *            The Filter or null.
> >>> +     * @param target
> >>> +     *            an output stream.
> >>> +     * @param follow
> >>> +     *            If true will follow changes to the underlying
> output stream.
> >>> +     *            Use false as the default.
> >>> +     * @param name
> >>> +     *            The name of the Appender (required).
> >>> +     * @param ignore
> >>> +     *            If {@code "true"} (default) exceptions encountered
> when
> >>> +     *            appending events are logged; otherwise they are
> propagated to
> >>> +     *            the caller. Use true as the default.
> >>> +     * @return The ConsoleAppender.
> >>> +     */
> >>> +    @PluginFactory
> >>> +    public static OutputStreamAppender createAppender(Layout<?
> extends Serializable> layout, final Filter filter,
> >>> +            final OutputStream target, final String name, final
> boolean follow, final boolean ignore) {
> >>> +        if (name == null) {
> >>> +            LOGGER.error("No name provided for OutputStreamAppender");
> >>> +            return null;
> >>> +        }
> >>> +        if (layout == null) {
> >>> +            layout = PatternLayout.createDefaultLayout();
> >>> +        }
> >>> +        return new OutputStreamAppender(name, layout, filter,
> getManager(target, follow, layout), ignore, null);
> >>> +    }
> >>> +
> >>> +    private static OutputStreamManager getManager(final OutputStream
> target, final boolean follow,
> >>> +            final Layout<? extends Serializable> layout) {
> >>> +        final OutputStream os = target == null ?
> NullOutputStream.getInstance() : new CloseShieldOutputStream(target);
> >>> +        final OutputStream targetRef = target == null ? os : target;
> >>> +        final String managerName = targetRef.getClass().getName() +
> "@" + Integer.toHexString(targetRef.hashCode())
> >>> +                + '.' + follow;
> >>> +        return OutputStreamManager.getManager(managerName, new
> FactoryData(os, managerName, layout), factory);
> >>> +    }
> >>> +
> >>> +    @PluginBuilderFactory
> >>> +    public static <B extends Builder<B>> B newBuilder() {
> >>> +        return new Builder<B>().asBuilder();
> >>> +    }
> >>> +
> >>> +    private OutputStreamAppender(final String name, final Layout<?
> extends Serializable> layout, final Filter filter,
> >>> +            final OutputStreamManager manager, final boolean
> ignoreExceptions, final Property[] properties) {
> >>> +        super(name, layout, filter, ignoreExceptions, true,
> properties, manager);
> >>> +    }
> >>> +
> >>> +}
> >>> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>> index 00af014..c1448bf 100644
> >>> ---
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>> +++
> b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> >>> @@ -1,108 +1,122 @@
> >>> -/*
> >>> - * 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.
> >>> - */
> >>> -package org.apache.logging.log4j.core.appender;
> >>> -
> >>> -import java.io.BufferedOutputStream;
> >>> -import java.io.ByteArrayOutputStream;
> >>> -import java.io.OutputStream;
> >>> -import java.sql.SQLException;
> >>> -
> >>> -import org.apache.logging.log4j.LogManager;
> >>> -import org.apache.logging.log4j.Logger;
> >>> -import org.apache.logging.log4j.core.Appender;
> >>> -import org.apache.logging.log4j.core.LoggerContext;
> >>> -import org.apache.logging.log4j.core.config.Configuration;
> >>> -import org.apache.logging.log4j.core.layout.PatternLayout;
> >>> -import org.junit.Assert;
> >>> -import org.junit.Rule;
> >>> -import org.junit.Test;
> >>> -import org.junit.rules.TestName;
> >>> -
> >>> -/**
> >>> - * Tests {@link OutputStreamAppender}.
> >>> - */
> >>> -public class OutputStreamAppenderTest {
> >>> -
> >>> -    private static final String TEST_MSG = "FOO ERROR";
> >>> -
> >>> -    @Rule
> >>> -    public TestName testName = new TestName();
> >>> -
> >>> -    private String getName(final OutputStream out) {
> >>> -        return out.getClass().getSimpleName() + "." +
> testName.getMethodName();
> >>> -    }
> >>> -
> >>> -    /**
> >>> -     * Tests that you can add an output stream appender dynamically.
> >>> -     */
> >>> -    private void addAppender(final OutputStream outputStream, final
> String outputStreamName) {
> >>> -        final LoggerContext context = LoggerContext.getContext(false);
> >>> -        final Configuration config = context.getConfiguration();
> >>> -        final PatternLayout layout =
> PatternLayout.createDefaultLayout(config);
> >>> -        final Appender appender =
> OutputStreamAppender.createAppender(layout, null, outputStream,
> outputStreamName, false, true);
> >>> -        appender.start();
> >>> -        config.addAppender(appender);
> >>> -        ConfigurationTestUtils.updateLoggers(appender, config);
> >>> -    }
> >>> -
> >>> -    @Test
> >>> -    public void testOutputStreamAppenderToBufferedOutputStream()
> throws SQLException {
> >>> -        final ByteArrayOutputStream out = new ByteArrayOutputStream();
> >>> -        final OutputStream os = new BufferedOutputStream(out);
> >>> -        final String name = getName(out);
> >>> -        final Logger logger = LogManager.getLogger(name);
> >>> -        addAppender(os, name);
> >>> -        logger.error(TEST_MSG);
> >>> -        final String actual = out.toString();
> >>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>> -    }
> >>> -
> >>> -    @Test
> >>> -    public void testOutputStreamAppenderToByteArrayOutputStream()
> throws SQLException {
> >>> -        final OutputStream out = new ByteArrayOutputStream();
> >>> -        final String name = getName(out);
> >>> -        final Logger logger = LogManager.getLogger(name);
> >>> -        addAppender(out, name);
> >>> -        logger.error(TEST_MSG);
> >>> -        final String actual = out.toString();
> >>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>> -    }
> >>> -
> >>> -    /**
> >>> -     * Validates that the code pattern we use to add an appender on
> the fly
> >>> -     * works with a basic appender that is not the new OutputStream
> appender or
> >>> -     * new Writer appender.
> >>> -     */
> >>> -    @Test
> >>> -    public void testUpdatePatternWithFileAppender() {
> >>> -        final LoggerContext ctx = (LoggerContext)
> LogManager.getContext(false);
> >>> -        final Configuration config = ctx.getConfiguration();
> >>> -        // @formatter:off
> >>> -        final Appender appender = FileAppender.newBuilder()
> >>> -        .withFileName("target/" + getClass().getName() + ".log")
> >>> -        .withAppend(false).setName("File").setIgnoreExceptions(false)
> >>> -            .withBufferedIo(false)
> >>> -            .withBufferSize(4000)
> >>> -            .setConfiguration(config)
> >>> -            .build();
> >>> -        // @formatter:on
> >>> -        appender.start();
> >>> -        config.addAppender(appender);
> >>> -        ConfigurationTestUtils.updateLoggers(appender, config);
> >>> -        LogManager.getLogger().error("FOO MSG");
> >>> -    }
> >>> -}
> >>> +/*
> >>> + * 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.
> >>> + */
> >>> +package org.apache.logging.log4j.core.appender;
> >>> +
> >>> +import java.io.BufferedOutputStream;
> >>> +import java.io.ByteArrayOutputStream;
> >>> +import java.io.OutputStream;
> >>> +import java.sql.SQLException;
> >>> +
> >>> +import org.apache.logging.log4j.LogManager;
> >>> +import org.apache.logging.log4j.Logger;
> >>> +import org.apache.logging.log4j.core.Appender;
> >>> +import org.apache.logging.log4j.core.LoggerContext;
> >>> +import org.apache.logging.log4j.core.config.Configuration;
> >>> +import org.apache.logging.log4j.core.filter.NoMarkerFilter;
> >>> +import org.apache.logging.log4j.core.layout.PatternLayout;
> >>> +import org.junit.Assert;
> >>> +import org.junit.Rule;
> >>> +import org.junit.Test;
> >>> +import org.junit.rules.TestName;
> >>> +
> >>> +/**
> >>> + * Tests {@link OutputStreamAppender}.
> >>> + */
> >>> +public class OutputStreamAppenderTest {
> >>> +
> >>> +    private static final String TEST_MSG = "FOO ERROR";
> >>> +
> >>> +    @Rule
> >>> +    public TestName testName = new TestName();
> >>> +
> >>> +    private String getName(final OutputStream out) {
> >>> +        return out.getClass().getSimpleName() + "." +
> testName.getMethodName();
> >>> +    }
> >>> +
> >>> +    /**
> >>> +     * Tests that you can add an output stream appender dynamically.
> >>> +     */
> >>> +    private void addAppender(final OutputStream outputStream, final
> String outputStreamName) {
> >>> +        final LoggerContext context = LoggerContext.getContext(false);
> >>> +        final Configuration config = context.getConfiguration();
> >>> +        final PatternLayout layout =
> PatternLayout.createDefaultLayout(config);
> >>> +        final Appender appender =
> OutputStreamAppender.createAppender(layout, null, outputStream,
> outputStreamName, false, true);
> >>> +        appender.start();
> >>> +        config.addAppender(appender);
> >>> +        ConfigurationTestUtils.updateLoggers(appender, config);
> >>> +    }
> >>> +
> >>> +    @Test
> >>> +    public void testBuildFilter() {
> >>> +        final NoMarkerFilter filter =
> NoMarkerFilter.newBuilder().build();
> >>> +        // @formatter:off
> >>> +        final OutputStreamAppender.Builder builder =
> OutputStreamAppender.newBuilder()
> >>> +                .setName("test")
> >>> +                .setFilter(filter);
> >>> +        // @formatter:on
> >>> +        Assert.assertEquals(filter, builder.getFilter());
> >>> +        final OutputStreamAppender appender = builder.build();
> >>> +        Assert.assertEquals(filter, appender.getFilter());
> >>> +    }
> >>> +
> >>> +    @Test
> >>> +    public void testOutputStreamAppenderToBufferedOutputStream()
> throws SQLException {
> >>> +        final ByteArrayOutputStream out = new ByteArrayOutputStream();
> >>> +        final OutputStream os = new BufferedOutputStream(out);
> >>> +        final String name = getName(out);
> >>> +        final Logger logger = LogManager.getLogger(name);
> >>> +        addAppender(os, name);
> >>> +        logger.error(TEST_MSG);
> >>> +        final String actual = out.toString();
> >>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>> +    }
> >>> +
> >>> +    @Test
> >>> +    public void testOutputStreamAppenderToByteArrayOutputStream()
> throws SQLException {
> >>> +        final OutputStream out = new ByteArrayOutputStream();
> >>> +        final String name = getName(out);
> >>> +        final Logger logger = LogManager.getLogger(name);
> >>> +        addAppender(out, name);
> >>> +        logger.error(TEST_MSG);
> >>> +        final String actual = out.toString();
> >>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> >>> +    }
> >>> +
> >>> +    /**
> >>> +     * Validates that the code pattern we use to add an appender on
> the fly
> >>> +     * works with a basic appender that is not the new OutputStream
> appender or
> >>> +     * new Writer appender.
> >>> +     */
> >>> +    @Test
> >>> +    public void testUpdatePatternWithFileAppender() {
> >>> +        final LoggerContext ctx = (LoggerContext)
> LogManager.getContext(false);
> >>> +        final Configuration config = ctx.getConfiguration();
> >>> +        // @formatter:off
> >>> +        final Appender appender = FileAppender.newBuilder()
> >>> +        .withFileName("target/" + getClass().getName() + ".log")
> >>> +        .withAppend(false).setName("File").setIgnoreExceptions(false)
> >>> +            .withBufferedIo(false)
> >>> +            .withBufferSize(4000)
> >>> +            .setConfiguration(config)
> >>> +            .build();
> >>> +        // @formatter:on
> >>> +        appender.start();
> >>> +        config.addAppender(appender);
> >>> +        ConfigurationTestUtils.updateLoggers(appender, config);
> >>> +        LogManager.getLogger().error("FOO MSG");
> >>> +    }
> >>> +}
> >>> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
> >>> index c3483bd..a9ec160 100644
> >>> --- a/src/changes/changes.xml
> >>> +++ b/src/changes/changes.xml
> >>> @@ -33,6 +33,9 @@
> >>>     <action issue="LOG4J2-2639" dev="rgoers" type="add">
> >>>       Add builder pattern to Logger interface.
> >>>     </action>
> >>> +      <action issue="LOG4J2-2673" dev="ggregory" type="fix"
> due-to="Yuichi Sugimura, Gary Gregory">
> >>> +        OutputStreamAppender.Builder ignores setFilter().
> >>> +      </action>
> >>>   </release>
> >>>   <release version="2.12.1" date="2019-08-06" description="GA Release
> 2.12.1">
> >>>     <action issue="LOG4J2-1946" dev="rgoers" type="fix" due-to="Igor
> Perelyotov">
> >>>
> >>>
> >>
> >>
> >>
> >
> >
> >
>
>
>

Re: [logging-log4j2] branch release-2.x updated: [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().

Posted by Ralph Goers <ra...@dslextreme.com>.
Gary,

Are you going to look into this?

Ralph

> On Aug 14, 2019, at 9:17 AM, Ralph Goers <ra...@dslextreme.com> wrote:
> 
> Any update on this? I’d like my builds to work again.
> 
> Ralph
> 
>> On Aug 13, 2019, at 4:29 PM, Ralph Goers <ra...@dslextreme.com> wrote:
>> 
>> Gary, 
>> 
>> It seems this change broker compatibility. Please see the Jenkins failure. You either need to resolve the code so compatibility is maintained or update revapi.json with the recommended changes.
>> 
>> Ralph
>> 
>>> On Aug 13, 2019, at 2:06 PM, ggregory@apache.org wrote:
>>> 
>>> This is an automated email from the ASF dual-hosted git repository.
>>> 
>>> ggregory pushed a commit to branch release-2.x
>>> in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
>>> 
>>> 
>>> The following commit(s) were added to refs/heads/release-2.x by this push:
>>>   new 4679a08  [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
>>> 4679a08 is described below
>>> 
>>> commit 4679a08d4899350f7ee19d050d2a96783b748066
>>> Author: Gary Gregory <ga...@gmail.com>
>>> AuthorDate: Tue Aug 13 17:06:48 2019 -0400
>>> 
>>>  [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
>>> 
>>>  Also allow a null output stream for convenience instead of an NPE.
>>> ---
>>> .../log4j/core/appender/OutputStreamAppender.java  | 351 +++++++++++----------
>>> .../core/appender/OutputStreamAppenderTest.java    | 230 +++++++-------
>>> src/changes/changes.xml                            |   3 +
>>> 3 files changed, 302 insertions(+), 282 deletions(-)
>>> 
>>> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>>> index 7dfd187..dc6f352 100644
>>> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>>> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>>> @@ -1,174 +1,177 @@
>>> -/*
>>> - * 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.
>>> - */
>>> -package org.apache.logging.log4j.core.appender;
>>> -
>>> -import java.io.OutputStream;
>>> -import java.io.Serializable;
>>> -
>>> -import org.apache.logging.log4j.core.Appender;
>>> -import org.apache.logging.log4j.core.Core;
>>> -import org.apache.logging.log4j.core.Filter;
>>> -import org.apache.logging.log4j.core.Layout;
>>> -import org.apache.logging.log4j.core.config.Property;
>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>> -import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
>>> -import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>>> -import org.apache.logging.log4j.core.layout.PatternLayout;
>>> -import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
>>> -
>>> -/**
>>> - * Appends log events to a given output stream using a layout.
>>> - * <p>
>>> - * Character encoding is handled within the Layout.
>>> - * </p>
>>> - */
>>> -@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
>>> -public final class OutputStreamAppender extends AbstractOutputStreamAppender<OutputStreamManager> {
>>> -
>>> -    /**
>>> -     * Builds OutputStreamAppender instances.
>>> -     */
>>> -    public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
>>> -            implements org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
>>> -
>>> -        private Filter filter;
>>> -
>>> -        private boolean follow = false;
>>> -
>>> -        private final boolean ignoreExceptions = true;
>>> -
>>> -        private OutputStream target;
>>> -
>>> -        @Override
>>> -        public OutputStreamAppender build() {
>>> -            final Layout<? extends Serializable> layout = getLayout();
>>> -            final Layout<? extends Serializable> actualLayout = layout == null ? PatternLayout.createDefaultLayout()
>>> -                    : layout;
>>> -            return new OutputStreamAppender(getName(), actualLayout, filter, getManager(target, follow, actualLayout),
>>> -                    ignoreExceptions, getPropertyArray());
>>> -        }
>>> -
>>> -        public B setFollow(final boolean shouldFollow) {
>>> -            this.follow = shouldFollow;
>>> -            return asBuilder();
>>> -        }
>>> -
>>> -        public B setTarget(final OutputStream aTarget) {
>>> -            this.target = aTarget;
>>> -            return asBuilder();
>>> -        }
>>> -    }
>>> -
>>> -    /**
>>> -     * Holds data to pass to factory method.
>>> -     */
>>> -    private static class FactoryData {
>>> -        private final Layout<? extends Serializable> layout;
>>> -        private final String name;
>>> -        private final OutputStream os;
>>> -
>>> -        /**
>>> -         * Builds instances.
>>> -         *
>>> -         * @param os
>>> -         *            The OutputStream.
>>> -         * @param type
>>> -         *            The name of the target.
>>> -         * @param layout
>>> -         *            A Serializable layout
>>> -         */
>>> -        public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
>>> -            this.os = os;
>>> -            this.name = type;
>>> -            this.layout = layout;
>>> -        }
>>> -    }
>>> -
>>> -    /**
>>> -     * Creates the manager.
>>> -     */
>>> -    private static class OutputStreamManagerFactory implements ManagerFactory<OutputStreamManager, FactoryData> {
>>> -
>>> -        /**
>>> -         * Creates an OutputStreamManager.
>>> -         *
>>> -         * @param name
>>> -         *            The name of the entity to manage.
>>> -         * @param data
>>> -         *            The data required to create the entity.
>>> -         * @return The OutputStreamManager
>>> -         */
>>> -        @Override
>>> -        public OutputStreamManager createManager(final String name, final FactoryData data) {
>>> -            return new OutputStreamManager(data.os, data.name, data.layout, true);
>>> -        }
>>> -    }
>>> -
>>> -    private static OutputStreamManagerFactory factory = new OutputStreamManagerFactory();
>>> -
>>> -    /**
>>> -     * Creates an OutputStream Appender.
>>> -     *
>>> -     * @param layout
>>> -     *            The layout to use or null to get the default layout.
>>> -     * @param filter
>>> -     *            The Filter or null.
>>> -     * @param target
>>> -     *            an output stream.
>>> -     * @param follow
>>> -     *            If true will follow changes to the underlying output stream.
>>> -     *            Use false as the default.
>>> -     * @param name
>>> -     *            The name of the Appender (required).
>>> -     * @param ignore
>>> -     *            If {@code "true"} (default) exceptions encountered when
>>> -     *            appending events are logged; otherwise they are propagated to
>>> -     *            the caller. Use true as the default.
>>> -     * @return The ConsoleAppender.
>>> -     */
>>> -    @PluginFactory
>>> -    public static OutputStreamAppender createAppender(Layout<? extends Serializable> layout, final Filter filter,
>>> -            final OutputStream target, final String name, final boolean follow, final boolean ignore) {
>>> -        if (name == null) {
>>> -            LOGGER.error("No name provided for OutputStreamAppender");
>>> -            return null;
>>> -        }
>>> -        if (layout == null) {
>>> -            layout = PatternLayout.createDefaultLayout();
>>> -        }
>>> -        return new OutputStreamAppender(name, layout, filter, getManager(target, follow, layout), ignore, null);
>>> -    }
>>> -
>>> -    private static OutputStreamManager getManager(final OutputStream target, final boolean follow,
>>> -            final Layout<? extends Serializable> layout) {
>>> -        final OutputStream os = new CloseShieldOutputStream(target);
>>> -        final String managerName = target.getClass().getName() + "@" + Integer.toHexString(target.hashCode()) + '.'
>>> -                + follow;
>>> -        return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory);
>>> -    }
>>> -
>>> -    @PluginBuilderFactory
>>> -    public static Builder newBuilder() {
>>> -        return new Builder();
>>> -    }
>>> -
>>> -    private OutputStreamAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
>>> -            final OutputStreamManager manager, final boolean ignoreExceptions, final Property[] properties) {
>>> -        super(name, layout, filter, ignoreExceptions, true, properties, manager);
>>> -    }
>>> -
>>> -}
>>> +/*
>>> + * 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.
>>> + */
>>> +package org.apache.logging.log4j.core.appender;
>>> +
>>> +import java.io.OutputStream;
>>> +import java.io.Serializable;
>>> +
>>> +import org.apache.logging.log4j.core.Appender;
>>> +import org.apache.logging.log4j.core.Core;
>>> +import org.apache.logging.log4j.core.Filter;
>>> +import org.apache.logging.log4j.core.Layout;
>>> +import org.apache.logging.log4j.core.config.Property;
>>> +import org.apache.logging.log4j.core.config.plugins.Plugin;
>>> +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
>>> +import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>>> +import org.apache.logging.log4j.core.layout.PatternLayout;
>>> +import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
>>> +import org.apache.logging.log4j.core.util.NullOutputStream;
>>> +
>>> +/**
>>> + * Appends log events to a given output stream using a layout.
>>> + * <p>
>>> + * Character encoding is handled within the Layout.
>>> + * </p>
>>> + */
>>> +@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
>>> +public final class OutputStreamAppender extends AbstractOutputStreamAppender<OutputStreamManager> {
>>> +
>>> +    /**
>>> +     * Builds OutputStreamAppender instances.
>>> +     *
>>> +     * @param <B>
>>> +     *            The type to build.
>>> +     */
>>> +    public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
>>> +            implements org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
>>> +
>>> +        private boolean follow = false;
>>> +
>>> +        private final boolean ignoreExceptions = true;
>>> +
>>> +        private OutputStream target;
>>> +
>>> +        @Override
>>> +        public OutputStreamAppender build() {
>>> +            final Layout<? extends Serializable> layout = getLayout();
>>> +            final Layout<? extends Serializable> actualLayout = layout == null ? PatternLayout.createDefaultLayout()
>>> +                    : layout;
>>> +            return new OutputStreamAppender(getName(), actualLayout, getFilter(), getManager(target, follow, actualLayout),
>>> +                    ignoreExceptions, getPropertyArray());
>>> +        }
>>> +
>>> +        public B setFollow(final boolean shouldFollow) {
>>> +            this.follow = shouldFollow;
>>> +            return asBuilder();
>>> +        }
>>> +
>>> +        public B setTarget(final OutputStream aTarget) {
>>> +            this.target = aTarget;
>>> +            return asBuilder();
>>> +        }
>>> +    }
>>> +
>>> +    /**
>>> +     * Holds data to pass to factory method.
>>> +     */
>>> +    private static class FactoryData {
>>> +        private final Layout<? extends Serializable> layout;
>>> +        private final String name;
>>> +        private final OutputStream os;
>>> +
>>> +        /**
>>> +         * Builds instances.
>>> +         *
>>> +         * @param os
>>> +         *            The OutputStream.
>>> +         * @param type
>>> +         *            The name of the target.
>>> +         * @param layout
>>> +         *            A Serializable layout
>>> +         */
>>> +        public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
>>> +            this.os = os;
>>> +            this.name = type;
>>> +            this.layout = layout;
>>> +        }
>>> +    }
>>> +
>>> +    /**
>>> +     * Creates the manager.
>>> +     */
>>> +    private static class OutputStreamManagerFactory implements ManagerFactory<OutputStreamManager, FactoryData> {
>>> +
>>> +        /**
>>> +         * Creates an OutputStreamManager.
>>> +         *
>>> +         * @param name
>>> +         *            The name of the entity to manage.
>>> +         * @param data
>>> +         *            The data required to create the entity.
>>> +         * @return The OutputStreamManager
>>> +         */
>>> +        @Override
>>> +        public OutputStreamManager createManager(final String name, final FactoryData data) {
>>> +            return new OutputStreamManager(data.os, data.name, data.layout, true);
>>> +        }
>>> +    }
>>> +
>>> +    private static OutputStreamManagerFactory factory = new OutputStreamManagerFactory();
>>> +
>>> +    /**
>>> +     * Creates an OutputStream Appender.
>>> +     *
>>> +     * @param layout
>>> +     *            The layout to use or null to get the default layout.
>>> +     * @param filter
>>> +     *            The Filter or null.
>>> +     * @param target
>>> +     *            an output stream.
>>> +     * @param follow
>>> +     *            If true will follow changes to the underlying output stream.
>>> +     *            Use false as the default.
>>> +     * @param name
>>> +     *            The name of the Appender (required).
>>> +     * @param ignore
>>> +     *            If {@code "true"} (default) exceptions encountered when
>>> +     *            appending events are logged; otherwise they are propagated to
>>> +     *            the caller. Use true as the default.
>>> +     * @return The ConsoleAppender.
>>> +     */
>>> +    @PluginFactory
>>> +    public static OutputStreamAppender createAppender(Layout<? extends Serializable> layout, final Filter filter,
>>> +            final OutputStream target, final String name, final boolean follow, final boolean ignore) {
>>> +        if (name == null) {
>>> +            LOGGER.error("No name provided for OutputStreamAppender");
>>> +            return null;
>>> +        }
>>> +        if (layout == null) {
>>> +            layout = PatternLayout.createDefaultLayout();
>>> +        }
>>> +        return new OutputStreamAppender(name, layout, filter, getManager(target, follow, layout), ignore, null);
>>> +    }
>>> +
>>> +    private static OutputStreamManager getManager(final OutputStream target, final boolean follow,
>>> +            final Layout<? extends Serializable> layout) {
>>> +        final OutputStream os = target == null ? NullOutputStream.getInstance() : new CloseShieldOutputStream(target);
>>> +        final OutputStream targetRef = target == null ? os : target;
>>> +        final String managerName = targetRef.getClass().getName() + "@" + Integer.toHexString(targetRef.hashCode())
>>> +                + '.' + follow;
>>> +        return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory);
>>> +    }
>>> +
>>> +    @PluginBuilderFactory
>>> +    public static <B extends Builder<B>> B newBuilder() {
>>> +        return new Builder<B>().asBuilder();
>>> +    }
>>> +
>>> +    private OutputStreamAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
>>> +            final OutputStreamManager manager, final boolean ignoreExceptions, final Property[] properties) {
>>> +        super(name, layout, filter, ignoreExceptions, true, properties, manager);
>>> +    }
>>> +
>>> +}
>>> diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>>> index 00af014..c1448bf 100644
>>> --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>>> +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>>> @@ -1,108 +1,122 @@
>>> -/*
>>> - * 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.
>>> - */
>>> -package org.apache.logging.log4j.core.appender;
>>> -
>>> -import java.io.BufferedOutputStream;
>>> -import java.io.ByteArrayOutputStream;
>>> -import java.io.OutputStream;
>>> -import java.sql.SQLException;
>>> -
>>> -import org.apache.logging.log4j.LogManager;
>>> -import org.apache.logging.log4j.Logger;
>>> -import org.apache.logging.log4j.core.Appender;
>>> -import org.apache.logging.log4j.core.LoggerContext;
>>> -import org.apache.logging.log4j.core.config.Configuration;
>>> -import org.apache.logging.log4j.core.layout.PatternLayout;
>>> -import org.junit.Assert;
>>> -import org.junit.Rule;
>>> -import org.junit.Test;
>>> -import org.junit.rules.TestName;
>>> -
>>> -/**
>>> - * Tests {@link OutputStreamAppender}.
>>> - */
>>> -public class OutputStreamAppenderTest {
>>> -
>>> -    private static final String TEST_MSG = "FOO ERROR";
>>> -
>>> -    @Rule
>>> -    public TestName testName = new TestName();
>>> -
>>> -    private String getName(final OutputStream out) {
>>> -        return out.getClass().getSimpleName() + "." + testName.getMethodName();
>>> -    }
>>> -
>>> -    /**
>>> -     * Tests that you can add an output stream appender dynamically.
>>> -     */
>>> -    private void addAppender(final OutputStream outputStream, final String outputStreamName) {
>>> -        final LoggerContext context = LoggerContext.getContext(false);
>>> -        final Configuration config = context.getConfiguration();
>>> -        final PatternLayout layout = PatternLayout.createDefaultLayout(config);
>>> -        final Appender appender = OutputStreamAppender.createAppender(layout, null, outputStream, outputStreamName, false, true);
>>> -        appender.start();
>>> -        config.addAppender(appender);
>>> -        ConfigurationTestUtils.updateLoggers(appender, config);
>>> -    }
>>> -
>>> -    @Test
>>> -    public void testOutputStreamAppenderToBufferedOutputStream() throws SQLException {
>>> -        final ByteArrayOutputStream out = new ByteArrayOutputStream();
>>> -        final OutputStream os = new BufferedOutputStream(out);
>>> -        final String name = getName(out);
>>> -        final Logger logger = LogManager.getLogger(name);
>>> -        addAppender(os, name);
>>> -        logger.error(TEST_MSG);
>>> -        final String actual = out.toString();
>>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>>> -    }
>>> -
>>> -    @Test
>>> -    public void testOutputStreamAppenderToByteArrayOutputStream() throws SQLException {
>>> -        final OutputStream out = new ByteArrayOutputStream();
>>> -        final String name = getName(out);
>>> -        final Logger logger = LogManager.getLogger(name);
>>> -        addAppender(out, name);
>>> -        logger.error(TEST_MSG);
>>> -        final String actual = out.toString();
>>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>>> -    }
>>> -
>>> -    /**
>>> -     * Validates that the code pattern we use to add an appender on the fly
>>> -     * works with a basic appender that is not the new OutputStream appender or
>>> -     * new Writer appender.
>>> -     */
>>> -    @Test
>>> -    public void testUpdatePatternWithFileAppender() {
>>> -        final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
>>> -        final Configuration config = ctx.getConfiguration();
>>> -        // @formatter:off
>>> -        final Appender appender = FileAppender.newBuilder()
>>> -        .withFileName("target/" + getClass().getName() + ".log")
>>> -        .withAppend(false).setName("File").setIgnoreExceptions(false)
>>> -            .withBufferedIo(false)
>>> -            .withBufferSize(4000)
>>> -            .setConfiguration(config)
>>> -            .build();
>>> -        // @formatter:on
>>> -        appender.start();
>>> -        config.addAppender(appender);
>>> -        ConfigurationTestUtils.updateLoggers(appender, config);
>>> -        LogManager.getLogger().error("FOO MSG");
>>> -    }
>>> -}
>>> +/*
>>> + * 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.
>>> + */
>>> +package org.apache.logging.log4j.core.appender;
>>> +
>>> +import java.io.BufferedOutputStream;
>>> +import java.io.ByteArrayOutputStream;
>>> +import java.io.OutputStream;
>>> +import java.sql.SQLException;
>>> +
>>> +import org.apache.logging.log4j.LogManager;
>>> +import org.apache.logging.log4j.Logger;
>>> +import org.apache.logging.log4j.core.Appender;
>>> +import org.apache.logging.log4j.core.LoggerContext;
>>> +import org.apache.logging.log4j.core.config.Configuration;
>>> +import org.apache.logging.log4j.core.filter.NoMarkerFilter;
>>> +import org.apache.logging.log4j.core.layout.PatternLayout;
>>> +import org.junit.Assert;
>>> +import org.junit.Rule;
>>> +import org.junit.Test;
>>> +import org.junit.rules.TestName;
>>> +
>>> +/**
>>> + * Tests {@link OutputStreamAppender}.
>>> + */
>>> +public class OutputStreamAppenderTest {
>>> +
>>> +    private static final String TEST_MSG = "FOO ERROR";
>>> +
>>> +    @Rule
>>> +    public TestName testName = new TestName();
>>> +
>>> +    private String getName(final OutputStream out) {
>>> +        return out.getClass().getSimpleName() + "." + testName.getMethodName();
>>> +    }
>>> +
>>> +    /**
>>> +     * Tests that you can add an output stream appender dynamically.
>>> +     */
>>> +    private void addAppender(final OutputStream outputStream, final String outputStreamName) {
>>> +        final LoggerContext context = LoggerContext.getContext(false);
>>> +        final Configuration config = context.getConfiguration();
>>> +        final PatternLayout layout = PatternLayout.createDefaultLayout(config);
>>> +        final Appender appender = OutputStreamAppender.createAppender(layout, null, outputStream, outputStreamName, false, true);
>>> +        appender.start();
>>> +        config.addAppender(appender);
>>> +        ConfigurationTestUtils.updateLoggers(appender, config);
>>> +    }
>>> +
>>> +    @Test
>>> +    public void testBuildFilter() {
>>> +        final NoMarkerFilter filter = NoMarkerFilter.newBuilder().build();
>>> +        // @formatter:off
>>> +        final OutputStreamAppender.Builder builder = OutputStreamAppender.newBuilder()
>>> +                .setName("test")
>>> +                .setFilter(filter);
>>> +        // @formatter:on
>>> +        Assert.assertEquals(filter, builder.getFilter());
>>> +        final OutputStreamAppender appender = builder.build();
>>> +        Assert.assertEquals(filter, appender.getFilter());
>>> +    }
>>> +    
>>> +    @Test
>>> +    public void testOutputStreamAppenderToBufferedOutputStream() throws SQLException {
>>> +        final ByteArrayOutputStream out = new ByteArrayOutputStream();
>>> +        final OutputStream os = new BufferedOutputStream(out);
>>> +        final String name = getName(out);
>>> +        final Logger logger = LogManager.getLogger(name);
>>> +        addAppender(os, name);
>>> +        logger.error(TEST_MSG);
>>> +        final String actual = out.toString();
>>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>>> +    }
>>> +
>>> +    @Test
>>> +    public void testOutputStreamAppenderToByteArrayOutputStream() throws SQLException {
>>> +        final OutputStream out = new ByteArrayOutputStream();
>>> +        final String name = getName(out);
>>> +        final Logger logger = LogManager.getLogger(name);
>>> +        addAppender(out, name);
>>> +        logger.error(TEST_MSG);
>>> +        final String actual = out.toString();
>>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>>> +    }
>>> +
>>> +    /**
>>> +     * Validates that the code pattern we use to add an appender on the fly
>>> +     * works with a basic appender that is not the new OutputStream appender or
>>> +     * new Writer appender.
>>> +     */
>>> +    @Test
>>> +    public void testUpdatePatternWithFileAppender() {
>>> +        final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
>>> +        final Configuration config = ctx.getConfiguration();
>>> +        // @formatter:off
>>> +        final Appender appender = FileAppender.newBuilder()
>>> +        .withFileName("target/" + getClass().getName() + ".log")
>>> +        .withAppend(false).setName("File").setIgnoreExceptions(false)
>>> +            .withBufferedIo(false)
>>> +            .withBufferSize(4000)
>>> +            .setConfiguration(config)
>>> +            .build();
>>> +        // @formatter:on
>>> +        appender.start();
>>> +        config.addAppender(appender);
>>> +        ConfigurationTestUtils.updateLoggers(appender, config);
>>> +        LogManager.getLogger().error("FOO MSG");
>>> +    }
>>> +}
>>> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
>>> index c3483bd..a9ec160 100644
>>> --- a/src/changes/changes.xml
>>> +++ b/src/changes/changes.xml
>>> @@ -33,6 +33,9 @@
>>>     <action issue="LOG4J2-2639" dev="rgoers" type="add">
>>>       Add builder pattern to Logger interface.
>>>     </action>
>>> +      <action issue="LOG4J2-2673" dev="ggregory" type="fix" due-to="Yuichi Sugimura, Gary Gregory">
>>> +        OutputStreamAppender.Builder ignores setFilter().
>>> +      </action>
>>>   </release>
>>>   <release version="2.12.1" date="2019-08-06" description="GA Release 2.12.1">
>>>     <action issue="LOG4J2-1946" dev="rgoers" type="fix" due-to="Igor Perelyotov">
>>> 
>>> 
>> 
>> 
>> 
> 
> 
> 



Re: [logging-log4j2] branch release-2.x updated: [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().

Posted by Ralph Goers <ra...@dslextreme.com>.
Any update on this? I’d like my builds to work again.

Ralph

> On Aug 13, 2019, at 4:29 PM, Ralph Goers <ra...@dslextreme.com> wrote:
> 
> Gary, 
> 
> It seems this change broker compatibility. Please see the Jenkins failure. You either need to resolve the code so compatibility is maintained or update revapi.json with the recommended changes.
> 
> Ralph
> 
>> On Aug 13, 2019, at 2:06 PM, ggregory@apache.org wrote:
>> 
>> This is an automated email from the ASF dual-hosted git repository.
>> 
>> ggregory pushed a commit to branch release-2.x
>> in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
>> 
>> 
>> The following commit(s) were added to refs/heads/release-2.x by this push:
>>    new 4679a08  [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
>> 4679a08 is described below
>> 
>> commit 4679a08d4899350f7ee19d050d2a96783b748066
>> Author: Gary Gregory <ga...@gmail.com>
>> AuthorDate: Tue Aug 13 17:06:48 2019 -0400
>> 
>>   [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
>> 
>>   Also allow a null output stream for convenience instead of an NPE.
>> ---
>> .../log4j/core/appender/OutputStreamAppender.java  | 351 +++++++++++----------
>> .../core/appender/OutputStreamAppenderTest.java    | 230 +++++++-------
>> src/changes/changes.xml                            |   3 +
>> 3 files changed, 302 insertions(+), 282 deletions(-)
>> 
>> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>> index 7dfd187..dc6f352 100644
>> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>> @@ -1,174 +1,177 @@
>> -/*
>> - * 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.
>> - */
>> -package org.apache.logging.log4j.core.appender;
>> -
>> -import java.io.OutputStream;
>> -import java.io.Serializable;
>> -
>> -import org.apache.logging.log4j.core.Appender;
>> -import org.apache.logging.log4j.core.Core;
>> -import org.apache.logging.log4j.core.Filter;
>> -import org.apache.logging.log4j.core.Layout;
>> -import org.apache.logging.log4j.core.config.Property;
>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>> -import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
>> -import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>> -import org.apache.logging.log4j.core.layout.PatternLayout;
>> -import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
>> -
>> -/**
>> - * Appends log events to a given output stream using a layout.
>> - * <p>
>> - * Character encoding is handled within the Layout.
>> - * </p>
>> - */
>> -@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
>> -public final class OutputStreamAppender extends AbstractOutputStreamAppender<OutputStreamManager> {
>> -
>> -    /**
>> -     * Builds OutputStreamAppender instances.
>> -     */
>> -    public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
>> -            implements org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
>> -
>> -        private Filter filter;
>> -
>> -        private boolean follow = false;
>> -
>> -        private final boolean ignoreExceptions = true;
>> -
>> -        private OutputStream target;
>> -
>> -        @Override
>> -        public OutputStreamAppender build() {
>> -            final Layout<? extends Serializable> layout = getLayout();
>> -            final Layout<? extends Serializable> actualLayout = layout == null ? PatternLayout.createDefaultLayout()
>> -                    : layout;
>> -            return new OutputStreamAppender(getName(), actualLayout, filter, getManager(target, follow, actualLayout),
>> -                    ignoreExceptions, getPropertyArray());
>> -        }
>> -
>> -        public B setFollow(final boolean shouldFollow) {
>> -            this.follow = shouldFollow;
>> -            return asBuilder();
>> -        }
>> -
>> -        public B setTarget(final OutputStream aTarget) {
>> -            this.target = aTarget;
>> -            return asBuilder();
>> -        }
>> -    }
>> -
>> -    /**
>> -     * Holds data to pass to factory method.
>> -     */
>> -    private static class FactoryData {
>> -        private final Layout<? extends Serializable> layout;
>> -        private final String name;
>> -        private final OutputStream os;
>> -
>> -        /**
>> -         * Builds instances.
>> -         *
>> -         * @param os
>> -         *            The OutputStream.
>> -         * @param type
>> -         *            The name of the target.
>> -         * @param layout
>> -         *            A Serializable layout
>> -         */
>> -        public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
>> -            this.os = os;
>> -            this.name = type;
>> -            this.layout = layout;
>> -        }
>> -    }
>> -
>> -    /**
>> -     * Creates the manager.
>> -     */
>> -    private static class OutputStreamManagerFactory implements ManagerFactory<OutputStreamManager, FactoryData> {
>> -
>> -        /**
>> -         * Creates an OutputStreamManager.
>> -         *
>> -         * @param name
>> -         *            The name of the entity to manage.
>> -         * @param data
>> -         *            The data required to create the entity.
>> -         * @return The OutputStreamManager
>> -         */
>> -        @Override
>> -        public OutputStreamManager createManager(final String name, final FactoryData data) {
>> -            return new OutputStreamManager(data.os, data.name, data.layout, true);
>> -        }
>> -    }
>> -
>> -    private static OutputStreamManagerFactory factory = new OutputStreamManagerFactory();
>> -
>> -    /**
>> -     * Creates an OutputStream Appender.
>> -     *
>> -     * @param layout
>> -     *            The layout to use or null to get the default layout.
>> -     * @param filter
>> -     *            The Filter or null.
>> -     * @param target
>> -     *            an output stream.
>> -     * @param follow
>> -     *            If true will follow changes to the underlying output stream.
>> -     *            Use false as the default.
>> -     * @param name
>> -     *            The name of the Appender (required).
>> -     * @param ignore
>> -     *            If {@code "true"} (default) exceptions encountered when
>> -     *            appending events are logged; otherwise they are propagated to
>> -     *            the caller. Use true as the default.
>> -     * @return The ConsoleAppender.
>> -     */
>> -    @PluginFactory
>> -    public static OutputStreamAppender createAppender(Layout<? extends Serializable> layout, final Filter filter,
>> -            final OutputStream target, final String name, final boolean follow, final boolean ignore) {
>> -        if (name == null) {
>> -            LOGGER.error("No name provided for OutputStreamAppender");
>> -            return null;
>> -        }
>> -        if (layout == null) {
>> -            layout = PatternLayout.createDefaultLayout();
>> -        }
>> -        return new OutputStreamAppender(name, layout, filter, getManager(target, follow, layout), ignore, null);
>> -    }
>> -
>> -    private static OutputStreamManager getManager(final OutputStream target, final boolean follow,
>> -            final Layout<? extends Serializable> layout) {
>> -        final OutputStream os = new CloseShieldOutputStream(target);
>> -        final String managerName = target.getClass().getName() + "@" + Integer.toHexString(target.hashCode()) + '.'
>> -                + follow;
>> -        return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory);
>> -    }
>> -
>> -    @PluginBuilderFactory
>> -    public static Builder newBuilder() {
>> -        return new Builder();
>> -    }
>> -
>> -    private OutputStreamAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
>> -            final OutputStreamManager manager, final boolean ignoreExceptions, final Property[] properties) {
>> -        super(name, layout, filter, ignoreExceptions, true, properties, manager);
>> -    }
>> -
>> -}
>> +/*
>> + * 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.
>> + */
>> +package org.apache.logging.log4j.core.appender;
>> +
>> +import java.io.OutputStream;
>> +import java.io.Serializable;
>> +
>> +import org.apache.logging.log4j.core.Appender;
>> +import org.apache.logging.log4j.core.Core;
>> +import org.apache.logging.log4j.core.Filter;
>> +import org.apache.logging.log4j.core.Layout;
>> +import org.apache.logging.log4j.core.config.Property;
>> +import org.apache.logging.log4j.core.config.plugins.Plugin;
>> +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
>> +import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>> +import org.apache.logging.log4j.core.layout.PatternLayout;
>> +import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
>> +import org.apache.logging.log4j.core.util.NullOutputStream;
>> +
>> +/**
>> + * Appends log events to a given output stream using a layout.
>> + * <p>
>> + * Character encoding is handled within the Layout.
>> + * </p>
>> + */
>> +@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
>> +public final class OutputStreamAppender extends AbstractOutputStreamAppender<OutputStreamManager> {
>> +
>> +    /**
>> +     * Builds OutputStreamAppender instances.
>> +     *
>> +     * @param <B>
>> +     *            The type to build.
>> +     */
>> +    public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
>> +            implements org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
>> +
>> +        private boolean follow = false;
>> +
>> +        private final boolean ignoreExceptions = true;
>> +
>> +        private OutputStream target;
>> +
>> +        @Override
>> +        public OutputStreamAppender build() {
>> +            final Layout<? extends Serializable> layout = getLayout();
>> +            final Layout<? extends Serializable> actualLayout = layout == null ? PatternLayout.createDefaultLayout()
>> +                    : layout;
>> +            return new OutputStreamAppender(getName(), actualLayout, getFilter(), getManager(target, follow, actualLayout),
>> +                    ignoreExceptions, getPropertyArray());
>> +        }
>> +
>> +        public B setFollow(final boolean shouldFollow) {
>> +            this.follow = shouldFollow;
>> +            return asBuilder();
>> +        }
>> +
>> +        public B setTarget(final OutputStream aTarget) {
>> +            this.target = aTarget;
>> +            return asBuilder();
>> +        }
>> +    }
>> +
>> +    /**
>> +     * Holds data to pass to factory method.
>> +     */
>> +    private static class FactoryData {
>> +        private final Layout<? extends Serializable> layout;
>> +        private final String name;
>> +        private final OutputStream os;
>> +
>> +        /**
>> +         * Builds instances.
>> +         *
>> +         * @param os
>> +         *            The OutputStream.
>> +         * @param type
>> +         *            The name of the target.
>> +         * @param layout
>> +         *            A Serializable layout
>> +         */
>> +        public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
>> +            this.os = os;
>> +            this.name = type;
>> +            this.layout = layout;
>> +        }
>> +    }
>> +
>> +    /**
>> +     * Creates the manager.
>> +     */
>> +    private static class OutputStreamManagerFactory implements ManagerFactory<OutputStreamManager, FactoryData> {
>> +
>> +        /**
>> +         * Creates an OutputStreamManager.
>> +         *
>> +         * @param name
>> +         *            The name of the entity to manage.
>> +         * @param data
>> +         *            The data required to create the entity.
>> +         * @return The OutputStreamManager
>> +         */
>> +        @Override
>> +        public OutputStreamManager createManager(final String name, final FactoryData data) {
>> +            return new OutputStreamManager(data.os, data.name, data.layout, true);
>> +        }
>> +    }
>> +
>> +    private static OutputStreamManagerFactory factory = new OutputStreamManagerFactory();
>> +
>> +    /**
>> +     * Creates an OutputStream Appender.
>> +     *
>> +     * @param layout
>> +     *            The layout to use or null to get the default layout.
>> +     * @param filter
>> +     *            The Filter or null.
>> +     * @param target
>> +     *            an output stream.
>> +     * @param follow
>> +     *            If true will follow changes to the underlying output stream.
>> +     *            Use false as the default.
>> +     * @param name
>> +     *            The name of the Appender (required).
>> +     * @param ignore
>> +     *            If {@code "true"} (default) exceptions encountered when
>> +     *            appending events are logged; otherwise they are propagated to
>> +     *            the caller. Use true as the default.
>> +     * @return The ConsoleAppender.
>> +     */
>> +    @PluginFactory
>> +    public static OutputStreamAppender createAppender(Layout<? extends Serializable> layout, final Filter filter,
>> +            final OutputStream target, final String name, final boolean follow, final boolean ignore) {
>> +        if (name == null) {
>> +            LOGGER.error("No name provided for OutputStreamAppender");
>> +            return null;
>> +        }
>> +        if (layout == null) {
>> +            layout = PatternLayout.createDefaultLayout();
>> +        }
>> +        return new OutputStreamAppender(name, layout, filter, getManager(target, follow, layout), ignore, null);
>> +    }
>> +
>> +    private static OutputStreamManager getManager(final OutputStream target, final boolean follow,
>> +            final Layout<? extends Serializable> layout) {
>> +        final OutputStream os = target == null ? NullOutputStream.getInstance() : new CloseShieldOutputStream(target);
>> +        final OutputStream targetRef = target == null ? os : target;
>> +        final String managerName = targetRef.getClass().getName() + "@" + Integer.toHexString(targetRef.hashCode())
>> +                + '.' + follow;
>> +        return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory);
>> +    }
>> +
>> +    @PluginBuilderFactory
>> +    public static <B extends Builder<B>> B newBuilder() {
>> +        return new Builder<B>().asBuilder();
>> +    }
>> +
>> +    private OutputStreamAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
>> +            final OutputStreamManager manager, final boolean ignoreExceptions, final Property[] properties) {
>> +        super(name, layout, filter, ignoreExceptions, true, properties, manager);
>> +    }
>> +
>> +}
>> diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>> index 00af014..c1448bf 100644
>> --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>> +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>> @@ -1,108 +1,122 @@
>> -/*
>> - * 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.
>> - */
>> -package org.apache.logging.log4j.core.appender;
>> -
>> -import java.io.BufferedOutputStream;
>> -import java.io.ByteArrayOutputStream;
>> -import java.io.OutputStream;
>> -import java.sql.SQLException;
>> -
>> -import org.apache.logging.log4j.LogManager;
>> -import org.apache.logging.log4j.Logger;
>> -import org.apache.logging.log4j.core.Appender;
>> -import org.apache.logging.log4j.core.LoggerContext;
>> -import org.apache.logging.log4j.core.config.Configuration;
>> -import org.apache.logging.log4j.core.layout.PatternLayout;
>> -import org.junit.Assert;
>> -import org.junit.Rule;
>> -import org.junit.Test;
>> -import org.junit.rules.TestName;
>> -
>> -/**
>> - * Tests {@link OutputStreamAppender}.
>> - */
>> -public class OutputStreamAppenderTest {
>> -
>> -    private static final String TEST_MSG = "FOO ERROR";
>> -
>> -    @Rule
>> -    public TestName testName = new TestName();
>> -
>> -    private String getName(final OutputStream out) {
>> -        return out.getClass().getSimpleName() + "." + testName.getMethodName();
>> -    }
>> -
>> -    /**
>> -     * Tests that you can add an output stream appender dynamically.
>> -     */
>> -    private void addAppender(final OutputStream outputStream, final String outputStreamName) {
>> -        final LoggerContext context = LoggerContext.getContext(false);
>> -        final Configuration config = context.getConfiguration();
>> -        final PatternLayout layout = PatternLayout.createDefaultLayout(config);
>> -        final Appender appender = OutputStreamAppender.createAppender(layout, null, outputStream, outputStreamName, false, true);
>> -        appender.start();
>> -        config.addAppender(appender);
>> -        ConfigurationTestUtils.updateLoggers(appender, config);
>> -    }
>> -
>> -    @Test
>> -    public void testOutputStreamAppenderToBufferedOutputStream() throws SQLException {
>> -        final ByteArrayOutputStream out = new ByteArrayOutputStream();
>> -        final OutputStream os = new BufferedOutputStream(out);
>> -        final String name = getName(out);
>> -        final Logger logger = LogManager.getLogger(name);
>> -        addAppender(os, name);
>> -        logger.error(TEST_MSG);
>> -        final String actual = out.toString();
>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>> -    }
>> -
>> -    @Test
>> -    public void testOutputStreamAppenderToByteArrayOutputStream() throws SQLException {
>> -        final OutputStream out = new ByteArrayOutputStream();
>> -        final String name = getName(out);
>> -        final Logger logger = LogManager.getLogger(name);
>> -        addAppender(out, name);
>> -        logger.error(TEST_MSG);
>> -        final String actual = out.toString();
>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>> -    }
>> -
>> -    /**
>> -     * Validates that the code pattern we use to add an appender on the fly
>> -     * works with a basic appender that is not the new OutputStream appender or
>> -     * new Writer appender.
>> -     */
>> -    @Test
>> -    public void testUpdatePatternWithFileAppender() {
>> -        final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
>> -        final Configuration config = ctx.getConfiguration();
>> -        // @formatter:off
>> -        final Appender appender = FileAppender.newBuilder()
>> -        .withFileName("target/" + getClass().getName() + ".log")
>> -        .withAppend(false).setName("File").setIgnoreExceptions(false)
>> -            .withBufferedIo(false)
>> -            .withBufferSize(4000)
>> -            .setConfiguration(config)
>> -            .build();
>> -        // @formatter:on
>> -        appender.start();
>> -        config.addAppender(appender);
>> -        ConfigurationTestUtils.updateLoggers(appender, config);
>> -        LogManager.getLogger().error("FOO MSG");
>> -    }
>> -}
>> +/*
>> + * 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.
>> + */
>> +package org.apache.logging.log4j.core.appender;
>> +
>> +import java.io.BufferedOutputStream;
>> +import java.io.ByteArrayOutputStream;
>> +import java.io.OutputStream;
>> +import java.sql.SQLException;
>> +
>> +import org.apache.logging.log4j.LogManager;
>> +import org.apache.logging.log4j.Logger;
>> +import org.apache.logging.log4j.core.Appender;
>> +import org.apache.logging.log4j.core.LoggerContext;
>> +import org.apache.logging.log4j.core.config.Configuration;
>> +import org.apache.logging.log4j.core.filter.NoMarkerFilter;
>> +import org.apache.logging.log4j.core.layout.PatternLayout;
>> +import org.junit.Assert;
>> +import org.junit.Rule;
>> +import org.junit.Test;
>> +import org.junit.rules.TestName;
>> +
>> +/**
>> + * Tests {@link OutputStreamAppender}.
>> + */
>> +public class OutputStreamAppenderTest {
>> +
>> +    private static final String TEST_MSG = "FOO ERROR";
>> +
>> +    @Rule
>> +    public TestName testName = new TestName();
>> +
>> +    private String getName(final OutputStream out) {
>> +        return out.getClass().getSimpleName() + "." + testName.getMethodName();
>> +    }
>> +
>> +    /**
>> +     * Tests that you can add an output stream appender dynamically.
>> +     */
>> +    private void addAppender(final OutputStream outputStream, final String outputStreamName) {
>> +        final LoggerContext context = LoggerContext.getContext(false);
>> +        final Configuration config = context.getConfiguration();
>> +        final PatternLayout layout = PatternLayout.createDefaultLayout(config);
>> +        final Appender appender = OutputStreamAppender.createAppender(layout, null, outputStream, outputStreamName, false, true);
>> +        appender.start();
>> +        config.addAppender(appender);
>> +        ConfigurationTestUtils.updateLoggers(appender, config);
>> +    }
>> +
>> +    @Test
>> +    public void testBuildFilter() {
>> +        final NoMarkerFilter filter = NoMarkerFilter.newBuilder().build();
>> +        // @formatter:off
>> +        final OutputStreamAppender.Builder builder = OutputStreamAppender.newBuilder()
>> +                .setName("test")
>> +                .setFilter(filter);
>> +        // @formatter:on
>> +        Assert.assertEquals(filter, builder.getFilter());
>> +        final OutputStreamAppender appender = builder.build();
>> +        Assert.assertEquals(filter, appender.getFilter());
>> +    }
>> +    
>> +    @Test
>> +    public void testOutputStreamAppenderToBufferedOutputStream() throws SQLException {
>> +        final ByteArrayOutputStream out = new ByteArrayOutputStream();
>> +        final OutputStream os = new BufferedOutputStream(out);
>> +        final String name = getName(out);
>> +        final Logger logger = LogManager.getLogger(name);
>> +        addAppender(os, name);
>> +        logger.error(TEST_MSG);
>> +        final String actual = out.toString();
>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>> +    }
>> +
>> +    @Test
>> +    public void testOutputStreamAppenderToByteArrayOutputStream() throws SQLException {
>> +        final OutputStream out = new ByteArrayOutputStream();
>> +        final String name = getName(out);
>> +        final Logger logger = LogManager.getLogger(name);
>> +        addAppender(out, name);
>> +        logger.error(TEST_MSG);
>> +        final String actual = out.toString();
>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>> +    }
>> +
>> +    /**
>> +     * Validates that the code pattern we use to add an appender on the fly
>> +     * works with a basic appender that is not the new OutputStream appender or
>> +     * new Writer appender.
>> +     */
>> +    @Test
>> +    public void testUpdatePatternWithFileAppender() {
>> +        final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
>> +        final Configuration config = ctx.getConfiguration();
>> +        // @formatter:off
>> +        final Appender appender = FileAppender.newBuilder()
>> +        .withFileName("target/" + getClass().getName() + ".log")
>> +        .withAppend(false).setName("File").setIgnoreExceptions(false)
>> +            .withBufferedIo(false)
>> +            .withBufferSize(4000)
>> +            .setConfiguration(config)
>> +            .build();
>> +        // @formatter:on
>> +        appender.start();
>> +        config.addAppender(appender);
>> +        ConfigurationTestUtils.updateLoggers(appender, config);
>> +        LogManager.getLogger().error("FOO MSG");
>> +    }
>> +}
>> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
>> index c3483bd..a9ec160 100644
>> --- a/src/changes/changes.xml
>> +++ b/src/changes/changes.xml
>> @@ -33,6 +33,9 @@
>>      <action issue="LOG4J2-2639" dev="rgoers" type="add">
>>        Add builder pattern to Logger interface.
>>      </action>
>> +      <action issue="LOG4J2-2673" dev="ggregory" type="fix" due-to="Yuichi Sugimura, Gary Gregory">
>> +        OutputStreamAppender.Builder ignores setFilter().
>> +      </action>
>>    </release>
>>    <release version="2.12.1" date="2019-08-06" description="GA Release 2.12.1">
>>      <action issue="LOG4J2-1946" dev="rgoers" type="fix" due-to="Igor Perelyotov">
>> 
>> 
> 
> 
> 



Re: [logging-log4j2] branch release-2.x updated: [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().

Posted by Ralph Goers <ra...@dslextreme.com>.
Also, if you had run the build before your commit you should have seen this failure.

Ralph

> On Aug 13, 2019, at 4:29 PM, Ralph Goers <ra...@dslextreme.com> wrote:
> 
> Gary, 
> 
> It seems this change broker compatibility. Please see the Jenkins failure. You either need to resolve the code so compatibility is maintained or update revapi.json with the recommended changes.
> 
> Ralph
> 
>> On Aug 13, 2019, at 2:06 PM, ggregory@apache.org wrote:
>> 
>> This is an automated email from the ASF dual-hosted git repository.
>> 
>> ggregory pushed a commit to branch release-2.x
>> in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
>> 
>> 
>> The following commit(s) were added to refs/heads/release-2.x by this push:
>>    new 4679a08  [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
>> 4679a08 is described below
>> 
>> commit 4679a08d4899350f7ee19d050d2a96783b748066
>> Author: Gary Gregory <ga...@gmail.com>
>> AuthorDate: Tue Aug 13 17:06:48 2019 -0400
>> 
>>   [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
>> 
>>   Also allow a null output stream for convenience instead of an NPE.
>> ---
>> .../log4j/core/appender/OutputStreamAppender.java  | 351 +++++++++++----------
>> .../core/appender/OutputStreamAppenderTest.java    | 230 +++++++-------
>> src/changes/changes.xml                            |   3 +
>> 3 files changed, 302 insertions(+), 282 deletions(-)
>> 
>> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>> index 7dfd187..dc6f352 100644
>> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
>> @@ -1,174 +1,177 @@
>> -/*
>> - * 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.
>> - */
>> -package org.apache.logging.log4j.core.appender;
>> -
>> -import java.io.OutputStream;
>> -import java.io.Serializable;
>> -
>> -import org.apache.logging.log4j.core.Appender;
>> -import org.apache.logging.log4j.core.Core;
>> -import org.apache.logging.log4j.core.Filter;
>> -import org.apache.logging.log4j.core.Layout;
>> -import org.apache.logging.log4j.core.config.Property;
>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>> -import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
>> -import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>> -import org.apache.logging.log4j.core.layout.PatternLayout;
>> -import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
>> -
>> -/**
>> - * Appends log events to a given output stream using a layout.
>> - * <p>
>> - * Character encoding is handled within the Layout.
>> - * </p>
>> - */
>> -@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
>> -public final class OutputStreamAppender extends AbstractOutputStreamAppender<OutputStreamManager> {
>> -
>> -    /**
>> -     * Builds OutputStreamAppender instances.
>> -     */
>> -    public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
>> -            implements org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
>> -
>> -        private Filter filter;
>> -
>> -        private boolean follow = false;
>> -
>> -        private final boolean ignoreExceptions = true;
>> -
>> -        private OutputStream target;
>> -
>> -        @Override
>> -        public OutputStreamAppender build() {
>> -            final Layout<? extends Serializable> layout = getLayout();
>> -            final Layout<? extends Serializable> actualLayout = layout == null ? PatternLayout.createDefaultLayout()
>> -                    : layout;
>> -            return new OutputStreamAppender(getName(), actualLayout, filter, getManager(target, follow, actualLayout),
>> -                    ignoreExceptions, getPropertyArray());
>> -        }
>> -
>> -        public B setFollow(final boolean shouldFollow) {
>> -            this.follow = shouldFollow;
>> -            return asBuilder();
>> -        }
>> -
>> -        public B setTarget(final OutputStream aTarget) {
>> -            this.target = aTarget;
>> -            return asBuilder();
>> -        }
>> -    }
>> -
>> -    /**
>> -     * Holds data to pass to factory method.
>> -     */
>> -    private static class FactoryData {
>> -        private final Layout<? extends Serializable> layout;
>> -        private final String name;
>> -        private final OutputStream os;
>> -
>> -        /**
>> -         * Builds instances.
>> -         *
>> -         * @param os
>> -         *            The OutputStream.
>> -         * @param type
>> -         *            The name of the target.
>> -         * @param layout
>> -         *            A Serializable layout
>> -         */
>> -        public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
>> -            this.os = os;
>> -            this.name = type;
>> -            this.layout = layout;
>> -        }
>> -    }
>> -
>> -    /**
>> -     * Creates the manager.
>> -     */
>> -    private static class OutputStreamManagerFactory implements ManagerFactory<OutputStreamManager, FactoryData> {
>> -
>> -        /**
>> -         * Creates an OutputStreamManager.
>> -         *
>> -         * @param name
>> -         *            The name of the entity to manage.
>> -         * @param data
>> -         *            The data required to create the entity.
>> -         * @return The OutputStreamManager
>> -         */
>> -        @Override
>> -        public OutputStreamManager createManager(final String name, final FactoryData data) {
>> -            return new OutputStreamManager(data.os, data.name, data.layout, true);
>> -        }
>> -    }
>> -
>> -    private static OutputStreamManagerFactory factory = new OutputStreamManagerFactory();
>> -
>> -    /**
>> -     * Creates an OutputStream Appender.
>> -     *
>> -     * @param layout
>> -     *            The layout to use or null to get the default layout.
>> -     * @param filter
>> -     *            The Filter or null.
>> -     * @param target
>> -     *            an output stream.
>> -     * @param follow
>> -     *            If true will follow changes to the underlying output stream.
>> -     *            Use false as the default.
>> -     * @param name
>> -     *            The name of the Appender (required).
>> -     * @param ignore
>> -     *            If {@code "true"} (default) exceptions encountered when
>> -     *            appending events are logged; otherwise they are propagated to
>> -     *            the caller. Use true as the default.
>> -     * @return The ConsoleAppender.
>> -     */
>> -    @PluginFactory
>> -    public static OutputStreamAppender createAppender(Layout<? extends Serializable> layout, final Filter filter,
>> -            final OutputStream target, final String name, final boolean follow, final boolean ignore) {
>> -        if (name == null) {
>> -            LOGGER.error("No name provided for OutputStreamAppender");
>> -            return null;
>> -        }
>> -        if (layout == null) {
>> -            layout = PatternLayout.createDefaultLayout();
>> -        }
>> -        return new OutputStreamAppender(name, layout, filter, getManager(target, follow, layout), ignore, null);
>> -    }
>> -
>> -    private static OutputStreamManager getManager(final OutputStream target, final boolean follow,
>> -            final Layout<? extends Serializable> layout) {
>> -        final OutputStream os = new CloseShieldOutputStream(target);
>> -        final String managerName = target.getClass().getName() + "@" + Integer.toHexString(target.hashCode()) + '.'
>> -                + follow;
>> -        return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory);
>> -    }
>> -
>> -    @PluginBuilderFactory
>> -    public static Builder newBuilder() {
>> -        return new Builder();
>> -    }
>> -
>> -    private OutputStreamAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
>> -            final OutputStreamManager manager, final boolean ignoreExceptions, final Property[] properties) {
>> -        super(name, layout, filter, ignoreExceptions, true, properties, manager);
>> -    }
>> -
>> -}
>> +/*
>> + * 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.
>> + */
>> +package org.apache.logging.log4j.core.appender;
>> +
>> +import java.io.OutputStream;
>> +import java.io.Serializable;
>> +
>> +import org.apache.logging.log4j.core.Appender;
>> +import org.apache.logging.log4j.core.Core;
>> +import org.apache.logging.log4j.core.Filter;
>> +import org.apache.logging.log4j.core.Layout;
>> +import org.apache.logging.log4j.core.config.Property;
>> +import org.apache.logging.log4j.core.config.plugins.Plugin;
>> +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
>> +import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>> +import org.apache.logging.log4j.core.layout.PatternLayout;
>> +import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
>> +import org.apache.logging.log4j.core.util.NullOutputStream;
>> +
>> +/**
>> + * Appends log events to a given output stream using a layout.
>> + * <p>
>> + * Character encoding is handled within the Layout.
>> + * </p>
>> + */
>> +@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
>> +public final class OutputStreamAppender extends AbstractOutputStreamAppender<OutputStreamManager> {
>> +
>> +    /**
>> +     * Builds OutputStreamAppender instances.
>> +     *
>> +     * @param <B>
>> +     *            The type to build.
>> +     */
>> +    public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
>> +            implements org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
>> +
>> +        private boolean follow = false;
>> +
>> +        private final boolean ignoreExceptions = true;
>> +
>> +        private OutputStream target;
>> +
>> +        @Override
>> +        public OutputStreamAppender build() {
>> +            final Layout<? extends Serializable> layout = getLayout();
>> +            final Layout<? extends Serializable> actualLayout = layout == null ? PatternLayout.createDefaultLayout()
>> +                    : layout;
>> +            return new OutputStreamAppender(getName(), actualLayout, getFilter(), getManager(target, follow, actualLayout),
>> +                    ignoreExceptions, getPropertyArray());
>> +        }
>> +
>> +        public B setFollow(final boolean shouldFollow) {
>> +            this.follow = shouldFollow;
>> +            return asBuilder();
>> +        }
>> +
>> +        public B setTarget(final OutputStream aTarget) {
>> +            this.target = aTarget;
>> +            return asBuilder();
>> +        }
>> +    }
>> +
>> +    /**
>> +     * Holds data to pass to factory method.
>> +     */
>> +    private static class FactoryData {
>> +        private final Layout<? extends Serializable> layout;
>> +        private final String name;
>> +        private final OutputStream os;
>> +
>> +        /**
>> +         * Builds instances.
>> +         *
>> +         * @param os
>> +         *            The OutputStream.
>> +         * @param type
>> +         *            The name of the target.
>> +         * @param layout
>> +         *            A Serializable layout
>> +         */
>> +        public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
>> +            this.os = os;
>> +            this.name = type;
>> +            this.layout = layout;
>> +        }
>> +    }
>> +
>> +    /**
>> +     * Creates the manager.
>> +     */
>> +    private static class OutputStreamManagerFactory implements ManagerFactory<OutputStreamManager, FactoryData> {
>> +
>> +        /**
>> +         * Creates an OutputStreamManager.
>> +         *
>> +         * @param name
>> +         *            The name of the entity to manage.
>> +         * @param data
>> +         *            The data required to create the entity.
>> +         * @return The OutputStreamManager
>> +         */
>> +        @Override
>> +        public OutputStreamManager createManager(final String name, final FactoryData data) {
>> +            return new OutputStreamManager(data.os, data.name, data.layout, true);
>> +        }
>> +    }
>> +
>> +    private static OutputStreamManagerFactory factory = new OutputStreamManagerFactory();
>> +
>> +    /**
>> +     * Creates an OutputStream Appender.
>> +     *
>> +     * @param layout
>> +     *            The layout to use or null to get the default layout.
>> +     * @param filter
>> +     *            The Filter or null.
>> +     * @param target
>> +     *            an output stream.
>> +     * @param follow
>> +     *            If true will follow changes to the underlying output stream.
>> +     *            Use false as the default.
>> +     * @param name
>> +     *            The name of the Appender (required).
>> +     * @param ignore
>> +     *            If {@code "true"} (default) exceptions encountered when
>> +     *            appending events are logged; otherwise they are propagated to
>> +     *            the caller. Use true as the default.
>> +     * @return The ConsoleAppender.
>> +     */
>> +    @PluginFactory
>> +    public static OutputStreamAppender createAppender(Layout<? extends Serializable> layout, final Filter filter,
>> +            final OutputStream target, final String name, final boolean follow, final boolean ignore) {
>> +        if (name == null) {
>> +            LOGGER.error("No name provided for OutputStreamAppender");
>> +            return null;
>> +        }
>> +        if (layout == null) {
>> +            layout = PatternLayout.createDefaultLayout();
>> +        }
>> +        return new OutputStreamAppender(name, layout, filter, getManager(target, follow, layout), ignore, null);
>> +    }
>> +
>> +    private static OutputStreamManager getManager(final OutputStream target, final boolean follow,
>> +            final Layout<? extends Serializable> layout) {
>> +        final OutputStream os = target == null ? NullOutputStream.getInstance() : new CloseShieldOutputStream(target);
>> +        final OutputStream targetRef = target == null ? os : target;
>> +        final String managerName = targetRef.getClass().getName() + "@" + Integer.toHexString(targetRef.hashCode())
>> +                + '.' + follow;
>> +        return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory);
>> +    }
>> +
>> +    @PluginBuilderFactory
>> +    public static <B extends Builder<B>> B newBuilder() {
>> +        return new Builder<B>().asBuilder();
>> +    }
>> +
>> +    private OutputStreamAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
>> +            final OutputStreamManager manager, final boolean ignoreExceptions, final Property[] properties) {
>> +        super(name, layout, filter, ignoreExceptions, true, properties, manager);
>> +    }
>> +
>> +}
>> diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>> index 00af014..c1448bf 100644
>> --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>> +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
>> @@ -1,108 +1,122 @@
>> -/*
>> - * 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.
>> - */
>> -package org.apache.logging.log4j.core.appender;
>> -
>> -import java.io.BufferedOutputStream;
>> -import java.io.ByteArrayOutputStream;
>> -import java.io.OutputStream;
>> -import java.sql.SQLException;
>> -
>> -import org.apache.logging.log4j.LogManager;
>> -import org.apache.logging.log4j.Logger;
>> -import org.apache.logging.log4j.core.Appender;
>> -import org.apache.logging.log4j.core.LoggerContext;
>> -import org.apache.logging.log4j.core.config.Configuration;
>> -import org.apache.logging.log4j.core.layout.PatternLayout;
>> -import org.junit.Assert;
>> -import org.junit.Rule;
>> -import org.junit.Test;
>> -import org.junit.rules.TestName;
>> -
>> -/**
>> - * Tests {@link OutputStreamAppender}.
>> - */
>> -public class OutputStreamAppenderTest {
>> -
>> -    private static final String TEST_MSG = "FOO ERROR";
>> -
>> -    @Rule
>> -    public TestName testName = new TestName();
>> -
>> -    private String getName(final OutputStream out) {
>> -        return out.getClass().getSimpleName() + "." + testName.getMethodName();
>> -    }
>> -
>> -    /**
>> -     * Tests that you can add an output stream appender dynamically.
>> -     */
>> -    private void addAppender(final OutputStream outputStream, final String outputStreamName) {
>> -        final LoggerContext context = LoggerContext.getContext(false);
>> -        final Configuration config = context.getConfiguration();
>> -        final PatternLayout layout = PatternLayout.createDefaultLayout(config);
>> -        final Appender appender = OutputStreamAppender.createAppender(layout, null, outputStream, outputStreamName, false, true);
>> -        appender.start();
>> -        config.addAppender(appender);
>> -        ConfigurationTestUtils.updateLoggers(appender, config);
>> -    }
>> -
>> -    @Test
>> -    public void testOutputStreamAppenderToBufferedOutputStream() throws SQLException {
>> -        final ByteArrayOutputStream out = new ByteArrayOutputStream();
>> -        final OutputStream os = new BufferedOutputStream(out);
>> -        final String name = getName(out);
>> -        final Logger logger = LogManager.getLogger(name);
>> -        addAppender(os, name);
>> -        logger.error(TEST_MSG);
>> -        final String actual = out.toString();
>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>> -    }
>> -
>> -    @Test
>> -    public void testOutputStreamAppenderToByteArrayOutputStream() throws SQLException {
>> -        final OutputStream out = new ByteArrayOutputStream();
>> -        final String name = getName(out);
>> -        final Logger logger = LogManager.getLogger(name);
>> -        addAppender(out, name);
>> -        logger.error(TEST_MSG);
>> -        final String actual = out.toString();
>> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>> -    }
>> -
>> -    /**
>> -     * Validates that the code pattern we use to add an appender on the fly
>> -     * works with a basic appender that is not the new OutputStream appender or
>> -     * new Writer appender.
>> -     */
>> -    @Test
>> -    public void testUpdatePatternWithFileAppender() {
>> -        final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
>> -        final Configuration config = ctx.getConfiguration();
>> -        // @formatter:off
>> -        final Appender appender = FileAppender.newBuilder()
>> -        .withFileName("target/" + getClass().getName() + ".log")
>> -        .withAppend(false).setName("File").setIgnoreExceptions(false)
>> -            .withBufferedIo(false)
>> -            .withBufferSize(4000)
>> -            .setConfiguration(config)
>> -            .build();
>> -        // @formatter:on
>> -        appender.start();
>> -        config.addAppender(appender);
>> -        ConfigurationTestUtils.updateLoggers(appender, config);
>> -        LogManager.getLogger().error("FOO MSG");
>> -    }
>> -}
>> +/*
>> + * 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.
>> + */
>> +package org.apache.logging.log4j.core.appender;
>> +
>> +import java.io.BufferedOutputStream;
>> +import java.io.ByteArrayOutputStream;
>> +import java.io.OutputStream;
>> +import java.sql.SQLException;
>> +
>> +import org.apache.logging.log4j.LogManager;
>> +import org.apache.logging.log4j.Logger;
>> +import org.apache.logging.log4j.core.Appender;
>> +import org.apache.logging.log4j.core.LoggerContext;
>> +import org.apache.logging.log4j.core.config.Configuration;
>> +import org.apache.logging.log4j.core.filter.NoMarkerFilter;
>> +import org.apache.logging.log4j.core.layout.PatternLayout;
>> +import org.junit.Assert;
>> +import org.junit.Rule;
>> +import org.junit.Test;
>> +import org.junit.rules.TestName;
>> +
>> +/**
>> + * Tests {@link OutputStreamAppender}.
>> + */
>> +public class OutputStreamAppenderTest {
>> +
>> +    private static final String TEST_MSG = "FOO ERROR";
>> +
>> +    @Rule
>> +    public TestName testName = new TestName();
>> +
>> +    private String getName(final OutputStream out) {
>> +        return out.getClass().getSimpleName() + "." + testName.getMethodName();
>> +    }
>> +
>> +    /**
>> +     * Tests that you can add an output stream appender dynamically.
>> +     */
>> +    private void addAppender(final OutputStream outputStream, final String outputStreamName) {
>> +        final LoggerContext context = LoggerContext.getContext(false);
>> +        final Configuration config = context.getConfiguration();
>> +        final PatternLayout layout = PatternLayout.createDefaultLayout(config);
>> +        final Appender appender = OutputStreamAppender.createAppender(layout, null, outputStream, outputStreamName, false, true);
>> +        appender.start();
>> +        config.addAppender(appender);
>> +        ConfigurationTestUtils.updateLoggers(appender, config);
>> +    }
>> +
>> +    @Test
>> +    public void testBuildFilter() {
>> +        final NoMarkerFilter filter = NoMarkerFilter.newBuilder().build();
>> +        // @formatter:off
>> +        final OutputStreamAppender.Builder builder = OutputStreamAppender.newBuilder()
>> +                .setName("test")
>> +                .setFilter(filter);
>> +        // @formatter:on
>> +        Assert.assertEquals(filter, builder.getFilter());
>> +        final OutputStreamAppender appender = builder.build();
>> +        Assert.assertEquals(filter, appender.getFilter());
>> +    }
>> +    
>> +    @Test
>> +    public void testOutputStreamAppenderToBufferedOutputStream() throws SQLException {
>> +        final ByteArrayOutputStream out = new ByteArrayOutputStream();
>> +        final OutputStream os = new BufferedOutputStream(out);
>> +        final String name = getName(out);
>> +        final Logger logger = LogManager.getLogger(name);
>> +        addAppender(os, name);
>> +        logger.error(TEST_MSG);
>> +        final String actual = out.toString();
>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>> +    }
>> +
>> +    @Test
>> +    public void testOutputStreamAppenderToByteArrayOutputStream() throws SQLException {
>> +        final OutputStream out = new ByteArrayOutputStream();
>> +        final String name = getName(out);
>> +        final Logger logger = LogManager.getLogger(name);
>> +        addAppender(out, name);
>> +        logger.error(TEST_MSG);
>> +        final String actual = out.toString();
>> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
>> +    }
>> +
>> +    /**
>> +     * Validates that the code pattern we use to add an appender on the fly
>> +     * works with a basic appender that is not the new OutputStream appender or
>> +     * new Writer appender.
>> +     */
>> +    @Test
>> +    public void testUpdatePatternWithFileAppender() {
>> +        final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
>> +        final Configuration config = ctx.getConfiguration();
>> +        // @formatter:off
>> +        final Appender appender = FileAppender.newBuilder()
>> +        .withFileName("target/" + getClass().getName() + ".log")
>> +        .withAppend(false).setName("File").setIgnoreExceptions(false)
>> +            .withBufferedIo(false)
>> +            .withBufferSize(4000)
>> +            .setConfiguration(config)
>> +            .build();
>> +        // @formatter:on
>> +        appender.start();
>> +        config.addAppender(appender);
>> +        ConfigurationTestUtils.updateLoggers(appender, config);
>> +        LogManager.getLogger().error("FOO MSG");
>> +    }
>> +}
>> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
>> index c3483bd..a9ec160 100644
>> --- a/src/changes/changes.xml
>> +++ b/src/changes/changes.xml
>> @@ -33,6 +33,9 @@
>>      <action issue="LOG4J2-2639" dev="rgoers" type="add">
>>        Add builder pattern to Logger interface.
>>      </action>
>> +      <action issue="LOG4J2-2673" dev="ggregory" type="fix" due-to="Yuichi Sugimura, Gary Gregory">
>> +        OutputStreamAppender.Builder ignores setFilter().
>> +      </action>
>>    </release>
>>    <release version="2.12.1" date="2019-08-06" description="GA Release 2.12.1">
>>      <action issue="LOG4J2-1946" dev="rgoers" type="fix" due-to="Igor Perelyotov">
>> 
>> 
> 
> 
> 



Re: [logging-log4j2] branch release-2.x updated: [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().

Posted by Ralph Goers <ra...@dslextreme.com>.
Gary, 

It seems this change broker compatibility. Please see the Jenkins failure. You either need to resolve the code so compatibility is maintained or update revapi.json with the recommended changes.

Ralph

> On Aug 13, 2019, at 2:06 PM, ggregory@apache.org wrote:
> 
> This is an automated email from the ASF dual-hosted git repository.
> 
> ggregory pushed a commit to branch release-2.x
> in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
> 
> 
> The following commit(s) were added to refs/heads/release-2.x by this push:
>     new 4679a08  [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
> 4679a08 is described below
> 
> commit 4679a08d4899350f7ee19d050d2a96783b748066
> Author: Gary Gregory <ga...@gmail.com>
> AuthorDate: Tue Aug 13 17:06:48 2019 -0400
> 
>    [LOG4J2-2673] OutputStreamAppender.Builder ignores setFilter().
> 
>    Also allow a null output stream for convenience instead of an NPE.
> ---
> .../log4j/core/appender/OutputStreamAppender.java  | 351 +++++++++++----------
> .../core/appender/OutputStreamAppenderTest.java    | 230 +++++++-------
> src/changes/changes.xml                            |   3 +
> 3 files changed, 302 insertions(+), 282 deletions(-)
> 
> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> index 7dfd187..dc6f352 100644
> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
> @@ -1,174 +1,177 @@
> -/*
> - * 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.
> - */
> -package org.apache.logging.log4j.core.appender;
> -
> -import java.io.OutputStream;
> -import java.io.Serializable;
> -
> -import org.apache.logging.log4j.core.Appender;
> -import org.apache.logging.log4j.core.Core;
> -import org.apache.logging.log4j.core.Filter;
> -import org.apache.logging.log4j.core.Layout;
> -import org.apache.logging.log4j.core.config.Property;
> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> -import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
> -import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> -import org.apache.logging.log4j.core.layout.PatternLayout;
> -import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
> -
> -/**
> - * Appends log events to a given output stream using a layout.
> - * <p>
> - * Character encoding is handled within the Layout.
> - * </p>
> - */
> -@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
> -public final class OutputStreamAppender extends AbstractOutputStreamAppender<OutputStreamManager> {
> -
> -    /**
> -     * Builds OutputStreamAppender instances.
> -     */
> -    public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
> -            implements org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
> -
> -        private Filter filter;
> -
> -        private boolean follow = false;
> -
> -        private final boolean ignoreExceptions = true;
> -
> -        private OutputStream target;
> -
> -        @Override
> -        public OutputStreamAppender build() {
> -            final Layout<? extends Serializable> layout = getLayout();
> -            final Layout<? extends Serializable> actualLayout = layout == null ? PatternLayout.createDefaultLayout()
> -                    : layout;
> -            return new OutputStreamAppender(getName(), actualLayout, filter, getManager(target, follow, actualLayout),
> -                    ignoreExceptions, getPropertyArray());
> -        }
> -
> -        public B setFollow(final boolean shouldFollow) {
> -            this.follow = shouldFollow;
> -            return asBuilder();
> -        }
> -
> -        public B setTarget(final OutputStream aTarget) {
> -            this.target = aTarget;
> -            return asBuilder();
> -        }
> -    }
> -
> -    /**
> -     * Holds data to pass to factory method.
> -     */
> -    private static class FactoryData {
> -        private final Layout<? extends Serializable> layout;
> -        private final String name;
> -        private final OutputStream os;
> -
> -        /**
> -         * Builds instances.
> -         *
> -         * @param os
> -         *            The OutputStream.
> -         * @param type
> -         *            The name of the target.
> -         * @param layout
> -         *            A Serializable layout
> -         */
> -        public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
> -            this.os = os;
> -            this.name = type;
> -            this.layout = layout;
> -        }
> -    }
> -
> -    /**
> -     * Creates the manager.
> -     */
> -    private static class OutputStreamManagerFactory implements ManagerFactory<OutputStreamManager, FactoryData> {
> -
> -        /**
> -         * Creates an OutputStreamManager.
> -         *
> -         * @param name
> -         *            The name of the entity to manage.
> -         * @param data
> -         *            The data required to create the entity.
> -         * @return The OutputStreamManager
> -         */
> -        @Override
> -        public OutputStreamManager createManager(final String name, final FactoryData data) {
> -            return new OutputStreamManager(data.os, data.name, data.layout, true);
> -        }
> -    }
> -
> -    private static OutputStreamManagerFactory factory = new OutputStreamManagerFactory();
> -
> -    /**
> -     * Creates an OutputStream Appender.
> -     *
> -     * @param layout
> -     *            The layout to use or null to get the default layout.
> -     * @param filter
> -     *            The Filter or null.
> -     * @param target
> -     *            an output stream.
> -     * @param follow
> -     *            If true will follow changes to the underlying output stream.
> -     *            Use false as the default.
> -     * @param name
> -     *            The name of the Appender (required).
> -     * @param ignore
> -     *            If {@code "true"} (default) exceptions encountered when
> -     *            appending events are logged; otherwise they are propagated to
> -     *            the caller. Use true as the default.
> -     * @return The ConsoleAppender.
> -     */
> -    @PluginFactory
> -    public static OutputStreamAppender createAppender(Layout<? extends Serializable> layout, final Filter filter,
> -            final OutputStream target, final String name, final boolean follow, final boolean ignore) {
> -        if (name == null) {
> -            LOGGER.error("No name provided for OutputStreamAppender");
> -            return null;
> -        }
> -        if (layout == null) {
> -            layout = PatternLayout.createDefaultLayout();
> -        }
> -        return new OutputStreamAppender(name, layout, filter, getManager(target, follow, layout), ignore, null);
> -    }
> -
> -    private static OutputStreamManager getManager(final OutputStream target, final boolean follow,
> -            final Layout<? extends Serializable> layout) {
> -        final OutputStream os = new CloseShieldOutputStream(target);
> -        final String managerName = target.getClass().getName() + "@" + Integer.toHexString(target.hashCode()) + '.'
> -                + follow;
> -        return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory);
> -    }
> -
> -    @PluginBuilderFactory
> -    public static Builder newBuilder() {
> -        return new Builder();
> -    }
> -
> -    private OutputStreamAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
> -            final OutputStreamManager manager, final boolean ignoreExceptions, final Property[] properties) {
> -        super(name, layout, filter, ignoreExceptions, true, properties, manager);
> -    }
> -
> -}
> +/*
> + * 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.
> + */
> +package org.apache.logging.log4j.core.appender;
> +
> +import java.io.OutputStream;
> +import java.io.Serializable;
> +
> +import org.apache.logging.log4j.core.Appender;
> +import org.apache.logging.log4j.core.Core;
> +import org.apache.logging.log4j.core.Filter;
> +import org.apache.logging.log4j.core.Layout;
> +import org.apache.logging.log4j.core.config.Property;
> +import org.apache.logging.log4j.core.config.plugins.Plugin;
> +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
> +import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> +import org.apache.logging.log4j.core.layout.PatternLayout;
> +import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
> +import org.apache.logging.log4j.core.util.NullOutputStream;
> +
> +/**
> + * Appends log events to a given output stream using a layout.
> + * <p>
> + * Character encoding is handled within the Layout.
> + * </p>
> + */
> +@Plugin(name = "OutputStream", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
> +public final class OutputStreamAppender extends AbstractOutputStreamAppender<OutputStreamManager> {
> +
> +    /**
> +     * Builds OutputStreamAppender instances.
> +     *
> +     * @param <B>
> +     *            The type to build.
> +     */
> +    public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
> +            implements org.apache.logging.log4j.core.util.Builder<OutputStreamAppender> {
> +
> +        private boolean follow = false;
> +
> +        private final boolean ignoreExceptions = true;
> +
> +        private OutputStream target;
> +
> +        @Override
> +        public OutputStreamAppender build() {
> +            final Layout<? extends Serializable> layout = getLayout();
> +            final Layout<? extends Serializable> actualLayout = layout == null ? PatternLayout.createDefaultLayout()
> +                    : layout;
> +            return new OutputStreamAppender(getName(), actualLayout, getFilter(), getManager(target, follow, actualLayout),
> +                    ignoreExceptions, getPropertyArray());
> +        }
> +
> +        public B setFollow(final boolean shouldFollow) {
> +            this.follow = shouldFollow;
> +            return asBuilder();
> +        }
> +
> +        public B setTarget(final OutputStream aTarget) {
> +            this.target = aTarget;
> +            return asBuilder();
> +        }
> +    }
> +
> +    /**
> +     * Holds data to pass to factory method.
> +     */
> +    private static class FactoryData {
> +        private final Layout<? extends Serializable> layout;
> +        private final String name;
> +        private final OutputStream os;
> +
> +        /**
> +         * Builds instances.
> +         *
> +         * @param os
> +         *            The OutputStream.
> +         * @param type
> +         *            The name of the target.
> +         * @param layout
> +         *            A Serializable layout
> +         */
> +        public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
> +            this.os = os;
> +            this.name = type;
> +            this.layout = layout;
> +        }
> +    }
> +
> +    /**
> +     * Creates the manager.
> +     */
> +    private static class OutputStreamManagerFactory implements ManagerFactory<OutputStreamManager, FactoryData> {
> +
> +        /**
> +         * Creates an OutputStreamManager.
> +         *
> +         * @param name
> +         *            The name of the entity to manage.
> +         * @param data
> +         *            The data required to create the entity.
> +         * @return The OutputStreamManager
> +         */
> +        @Override
> +        public OutputStreamManager createManager(final String name, final FactoryData data) {
> +            return new OutputStreamManager(data.os, data.name, data.layout, true);
> +        }
> +    }
> +
> +    private static OutputStreamManagerFactory factory = new OutputStreamManagerFactory();
> +
> +    /**
> +     * Creates an OutputStream Appender.
> +     *
> +     * @param layout
> +     *            The layout to use or null to get the default layout.
> +     * @param filter
> +     *            The Filter or null.
> +     * @param target
> +     *            an output stream.
> +     * @param follow
> +     *            If true will follow changes to the underlying output stream.
> +     *            Use false as the default.
> +     * @param name
> +     *            The name of the Appender (required).
> +     * @param ignore
> +     *            If {@code "true"} (default) exceptions encountered when
> +     *            appending events are logged; otherwise they are propagated to
> +     *            the caller. Use true as the default.
> +     * @return The ConsoleAppender.
> +     */
> +    @PluginFactory
> +    public static OutputStreamAppender createAppender(Layout<? extends Serializable> layout, final Filter filter,
> +            final OutputStream target, final String name, final boolean follow, final boolean ignore) {
> +        if (name == null) {
> +            LOGGER.error("No name provided for OutputStreamAppender");
> +            return null;
> +        }
> +        if (layout == null) {
> +            layout = PatternLayout.createDefaultLayout();
> +        }
> +        return new OutputStreamAppender(name, layout, filter, getManager(target, follow, layout), ignore, null);
> +    }
> +
> +    private static OutputStreamManager getManager(final OutputStream target, final boolean follow,
> +            final Layout<? extends Serializable> layout) {
> +        final OutputStream os = target == null ? NullOutputStream.getInstance() : new CloseShieldOutputStream(target);
> +        final OutputStream targetRef = target == null ? os : target;
> +        final String managerName = targetRef.getClass().getName() + "@" + Integer.toHexString(targetRef.hashCode())
> +                + '.' + follow;
> +        return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory);
> +    }
> +
> +    @PluginBuilderFactory
> +    public static <B extends Builder<B>> B newBuilder() {
> +        return new Builder<B>().asBuilder();
> +    }
> +
> +    private OutputStreamAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
> +            final OutputStreamManager manager, final boolean ignoreExceptions, final Property[] properties) {
> +        super(name, layout, filter, ignoreExceptions, true, properties, manager);
> +    }
> +
> +}
> diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> index 00af014..c1448bf 100644
> --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java
> @@ -1,108 +1,122 @@
> -/*
> - * 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.
> - */
> -package org.apache.logging.log4j.core.appender;
> -
> -import java.io.BufferedOutputStream;
> -import java.io.ByteArrayOutputStream;
> -import java.io.OutputStream;
> -import java.sql.SQLException;
> -
> -import org.apache.logging.log4j.LogManager;
> -import org.apache.logging.log4j.Logger;
> -import org.apache.logging.log4j.core.Appender;
> -import org.apache.logging.log4j.core.LoggerContext;
> -import org.apache.logging.log4j.core.config.Configuration;
> -import org.apache.logging.log4j.core.layout.PatternLayout;
> -import org.junit.Assert;
> -import org.junit.Rule;
> -import org.junit.Test;
> -import org.junit.rules.TestName;
> -
> -/**
> - * Tests {@link OutputStreamAppender}.
> - */
> -public class OutputStreamAppenderTest {
> -
> -    private static final String TEST_MSG = "FOO ERROR";
> -
> -    @Rule
> -    public TestName testName = new TestName();
> -
> -    private String getName(final OutputStream out) {
> -        return out.getClass().getSimpleName() + "." + testName.getMethodName();
> -    }
> -
> -    /**
> -     * Tests that you can add an output stream appender dynamically.
> -     */
> -    private void addAppender(final OutputStream outputStream, final String outputStreamName) {
> -        final LoggerContext context = LoggerContext.getContext(false);
> -        final Configuration config = context.getConfiguration();
> -        final PatternLayout layout = PatternLayout.createDefaultLayout(config);
> -        final Appender appender = OutputStreamAppender.createAppender(layout, null, outputStream, outputStreamName, false, true);
> -        appender.start();
> -        config.addAppender(appender);
> -        ConfigurationTestUtils.updateLoggers(appender, config);
> -    }
> -
> -    @Test
> -    public void testOutputStreamAppenderToBufferedOutputStream() throws SQLException {
> -        final ByteArrayOutputStream out = new ByteArrayOutputStream();
> -        final OutputStream os = new BufferedOutputStream(out);
> -        final String name = getName(out);
> -        final Logger logger = LogManager.getLogger(name);
> -        addAppender(os, name);
> -        logger.error(TEST_MSG);
> -        final String actual = out.toString();
> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> -    }
> -
> -    @Test
> -    public void testOutputStreamAppenderToByteArrayOutputStream() throws SQLException {
> -        final OutputStream out = new ByteArrayOutputStream();
> -        final String name = getName(out);
> -        final Logger logger = LogManager.getLogger(name);
> -        addAppender(out, name);
> -        logger.error(TEST_MSG);
> -        final String actual = out.toString();
> -        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> -    }
> -
> -    /**
> -     * Validates that the code pattern we use to add an appender on the fly
> -     * works with a basic appender that is not the new OutputStream appender or
> -     * new Writer appender.
> -     */
> -    @Test
> -    public void testUpdatePatternWithFileAppender() {
> -        final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
> -        final Configuration config = ctx.getConfiguration();
> -        // @formatter:off
> -        final Appender appender = FileAppender.newBuilder()
> -        .withFileName("target/" + getClass().getName() + ".log")
> -        .withAppend(false).setName("File").setIgnoreExceptions(false)
> -            .withBufferedIo(false)
> -            .withBufferSize(4000)
> -            .setConfiguration(config)
> -            .build();
> -        // @formatter:on
> -        appender.start();
> -        config.addAppender(appender);
> -        ConfigurationTestUtils.updateLoggers(appender, config);
> -        LogManager.getLogger().error("FOO MSG");
> -    }
> -}
> +/*
> + * 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.
> + */
> +package org.apache.logging.log4j.core.appender;
> +
> +import java.io.BufferedOutputStream;
> +import java.io.ByteArrayOutputStream;
> +import java.io.OutputStream;
> +import java.sql.SQLException;
> +
> +import org.apache.logging.log4j.LogManager;
> +import org.apache.logging.log4j.Logger;
> +import org.apache.logging.log4j.core.Appender;
> +import org.apache.logging.log4j.core.LoggerContext;
> +import org.apache.logging.log4j.core.config.Configuration;
> +import org.apache.logging.log4j.core.filter.NoMarkerFilter;
> +import org.apache.logging.log4j.core.layout.PatternLayout;
> +import org.junit.Assert;
> +import org.junit.Rule;
> +import org.junit.Test;
> +import org.junit.rules.TestName;
> +
> +/**
> + * Tests {@link OutputStreamAppender}.
> + */
> +public class OutputStreamAppenderTest {
> +
> +    private static final String TEST_MSG = "FOO ERROR";
> +
> +    @Rule
> +    public TestName testName = new TestName();
> +
> +    private String getName(final OutputStream out) {
> +        return out.getClass().getSimpleName() + "." + testName.getMethodName();
> +    }
> +
> +    /**
> +     * Tests that you can add an output stream appender dynamically.
> +     */
> +    private void addAppender(final OutputStream outputStream, final String outputStreamName) {
> +        final LoggerContext context = LoggerContext.getContext(false);
> +        final Configuration config = context.getConfiguration();
> +        final PatternLayout layout = PatternLayout.createDefaultLayout(config);
> +        final Appender appender = OutputStreamAppender.createAppender(layout, null, outputStream, outputStreamName, false, true);
> +        appender.start();
> +        config.addAppender(appender);
> +        ConfigurationTestUtils.updateLoggers(appender, config);
> +    }
> +
> +    @Test
> +    public void testBuildFilter() {
> +        final NoMarkerFilter filter = NoMarkerFilter.newBuilder().build();
> +        // @formatter:off
> +        final OutputStreamAppender.Builder builder = OutputStreamAppender.newBuilder()
> +                .setName("test")
> +                .setFilter(filter);
> +        // @formatter:on
> +        Assert.assertEquals(filter, builder.getFilter());
> +        final OutputStreamAppender appender = builder.build();
> +        Assert.assertEquals(filter, appender.getFilter());
> +    }
> +    
> +    @Test
> +    public void testOutputStreamAppenderToBufferedOutputStream() throws SQLException {
> +        final ByteArrayOutputStream out = new ByteArrayOutputStream();
> +        final OutputStream os = new BufferedOutputStream(out);
> +        final String name = getName(out);
> +        final Logger logger = LogManager.getLogger(name);
> +        addAppender(os, name);
> +        logger.error(TEST_MSG);
> +        final String actual = out.toString();
> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> +    }
> +
> +    @Test
> +    public void testOutputStreamAppenderToByteArrayOutputStream() throws SQLException {
> +        final OutputStream out = new ByteArrayOutputStream();
> +        final String name = getName(out);
> +        final Logger logger = LogManager.getLogger(name);
> +        addAppender(out, name);
> +        logger.error(TEST_MSG);
> +        final String actual = out.toString();
> +        Assert.assertTrue(actual, actual.contains(TEST_MSG));
> +    }
> +
> +    /**
> +     * Validates that the code pattern we use to add an appender on the fly
> +     * works with a basic appender that is not the new OutputStream appender or
> +     * new Writer appender.
> +     */
> +    @Test
> +    public void testUpdatePatternWithFileAppender() {
> +        final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
> +        final Configuration config = ctx.getConfiguration();
> +        // @formatter:off
> +        final Appender appender = FileAppender.newBuilder()
> +        .withFileName("target/" + getClass().getName() + ".log")
> +        .withAppend(false).setName("File").setIgnoreExceptions(false)
> +            .withBufferedIo(false)
> +            .withBufferSize(4000)
> +            .setConfiguration(config)
> +            .build();
> +        // @formatter:on
> +        appender.start();
> +        config.addAppender(appender);
> +        ConfigurationTestUtils.updateLoggers(appender, config);
> +        LogManager.getLogger().error("FOO MSG");
> +    }
> +}
> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
> index c3483bd..a9ec160 100644
> --- a/src/changes/changes.xml
> +++ b/src/changes/changes.xml
> @@ -33,6 +33,9 @@
>       <action issue="LOG4J2-2639" dev="rgoers" type="add">
>         Add builder pattern to Logger interface.
>       </action>
> +      <action issue="LOG4J2-2673" dev="ggregory" type="fix" due-to="Yuichi Sugimura, Gary Gregory">
> +        OutputStreamAppender.Builder ignores setFilter().
> +      </action>
>     </release>
>     <release version="2.12.1" date="2019-08-06" description="GA Release 2.12.1">
>       <action issue="LOG4J2-1946" dev="rgoers" type="fix" due-to="Igor Perelyotov">
> 
>