Can you provide documentation on using the builder?  I tried to implement 
something a few months ago using a builder and couldn’t quite figure it all out 
so I went back to using a factory.

Ralph

> On May 26, 2016, at 8:31 AM, Matt Sicker <[email protected]> wrote:
> 
> I prefer builders when you have more than 2 arguments to the factory. This is 
> based on Item 2 from Effective Java (prefer builders for constructors that 
> take a lot of arguments).
> 
> On 26 May 2016 at 10:24, Mikael Ståldal <[email protected] 
> <mailto:[email protected]>> wrote:
> Which one of builder and factory is preferred?
> 
> On Thu, May 26, 2016 at 5:22 PM, Matt Sicker <[email protected] 
> <mailto:[email protected]>> wrote:
> Just FYI, if you make a plugin builder, you don't need to make a plugin 
> factory as well. The builder is used first if available followed by the 
> factory method. Classes that have both are mainly for backwards compatibility.
> 
> ---------- Forwarded message ----------
> From: <[email protected] <mailto:[email protected]>>
> Date: 26 May 2016 at 10:12
> Subject: logging-log4j2 git commit: FastConsoleAppender
> To: [email protected] <mailto:[email protected]>
> 
> 
> Repository: logging-log4j2
> Updated Branches:
>   refs/heads/LOG4J2-1395 [created] 06c554689
> 
> 
> FastConsoleAppender
> 
> 
> Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo 
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo>
> Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/06c55468 
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/06c55468>
> Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/06c55468 
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/06c55468>
> Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/06c55468 
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/06c55468>
> 
> Branch: refs/heads/LOG4J2-1395
> Commit: 06c55468948efdce95a591801d5f9e2ffdb69dd4
> Parents: e012269
> Author: Mikael Ståldal <[email protected] 
> <mailto:[email protected]>>
> Authored: Thu May 26 17:12:33 2016 +0200
> Committer: Mikael Ståldal <[email protected] 
> <mailto:[email protected]>>
> Committed: Thu May 26 17:12:33 2016 +0200
> 
> ----------------------------------------------------------------------
>  .../core/appender/FastConsoleAppender.java      | 227 +++++++++++++++++++
>  .../jmh/Log4j2AppenderComparisonBenchmark.java  |  18 ++
>  .../resources/log4j2-appenderComparison.xml     |   6 +
>  3 files changed, 251 insertions(+)
> ----------------------------------------------------------------------
> 
> 
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/06c55468/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FastConsoleAppender.java
>  
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/06c55468/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FastConsoleAppender.java>
> ----------------------------------------------------------------------
> diff --git 
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FastConsoleAppender.java
>  
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FastConsoleAppender.java
> new file mode 100644
> index 0000000..a7cd905
> --- /dev/null
> +++ 
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FastConsoleAppender.java
> @@ -0,0 +1,227 @@
> +/*
> + * 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 
> <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.FileDescriptor;
> +import java.io.FileOutputStream;
> +import java.io.OutputStream;
> +import java.io.Serializable;
> +import java.util.concurrent.atomic.AtomicInteger;
> +
> +import org.apache.logging.log4j.core.Filter;
> +import org.apache.logging.log4j.core.Layout;
> +import org.apache.logging.log4j.core.config.plugins.Plugin;
> +import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
> +import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
> +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
> +import org.apache.logging.log4j.core.config.plugins.PluginElement;
> +import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> +import 
> org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
> +import org.apache.logging.log4j.core.layout.PatternLayout;
> +import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
> +
> +/**
> + * Appends log events to <code>System.out</code> or <code>System.err</code> 
> using a layout specified by the user. The
> + * default target is <code>System.out</code>.
> + */
> +@Plugin(name = "FastConsole", category = "Core", elementType = "appender", 
> printObject = true)
> +public final class FastConsoleAppender extends 
> AbstractOutputStreamAppender<OutputStreamManager> {
> +
> +    private static ConsoleManagerFactory factory = new 
> ConsoleManagerFactory();
> +    private static final Target DEFAULT_TARGET = Target.SYSTEM_OUT;
> +    private static final AtomicInteger COUNT = new AtomicInteger();
> +
> +    private final Target target;
> +
> +    /**
> +     * Enumeration of console destinations.
> +     */
> +    public enum Target {
> +        /** Standard output. */
> +        SYSTEM_OUT,
> +        /** Standard error output. */
> +        SYSTEM_ERR
> +    }
> +
> +    private FastConsoleAppender(final String name, final Layout<? extends 
> Serializable> layout, final Filter filter,
> +                                final OutputStreamManager manager, final 
> boolean ignoreExceptions, Target target) {
> +        super(name, layout, filter, ignoreExceptions, true, manager);
> +        this.target = target;
> +    }
> +
> +    /**
> +     * Creates a Console Appender.
> +     *
> +     * @param layout The layout to use (required).
> +     * @param filter The Filter or null.
> +     * @param target The target (SYSTEM_OUT or SYSTEM_ERR). The default is 
> SYSTEM_OUT.
> +     * @param name The name of the Appender (required).
> +     * @param ignoreExceptions If {@code "true"} (default) exceptions 
> encountered when appending events are logged; otherwise they
> +     *            are propagated to the caller.
> +     * @return The ConsoleAppender.
> +     */
> +    @PluginFactory
> +    public static FastConsoleAppender createAppender(
> +            // @formatter:off
> +            @PluginElement("Layout") Layout<? extends Serializable> layout,
> +            @PluginElement("Filter") final Filter filter,
> +            @PluginAttribute(value = "target") Target target,
> +            @PluginAttribute("name") final String name,
> +            @PluginAttribute(value = "ignoreExceptions", defaultBoolean = 
> true) final boolean ignoreExceptions) {
> +            // @formatter:on
> +        if (name == null) {
> +            LOGGER.error("No name provided for ConsoleAppender");
> +            return null;
> +        }
> +        if (layout == null) {
> +            layout = PatternLayout.createDefaultLayout();
> +        }
> +        target = target == null ? Target.SYSTEM_OUT : target;
> +        return new FastConsoleAppender(name, layout, filter, 
> getManager(target, layout), ignoreExceptions, target);
> +    }
> +
> +    public static FastConsoleAppender createDefaultAppenderForLayout(final 
> Layout<? extends Serializable> layout) {
> +        // this method cannot use the builder class without introducing an 
> infinite loop due to DefaultConfiguration
> +        return new FastConsoleAppender("DefaultConsole-" + 
> COUNT.incrementAndGet(), layout, null,
> +                getDefaultManager(DEFAULT_TARGET, layout), true, 
> DEFAULT_TARGET);
> +    }
> +
> +    @PluginBuilderFactory
> +    public static Builder newBuilder() {
> +        return new Builder();
> +    }
> +
> +    /**
> +     * Builds ConsoleAppender instances.
> +     */
> +    public static class Builder implements 
> org.apache.logging.log4j.core.util.Builder<FastConsoleAppender> {
> +
> +        @PluginElement("Layout")
> +        @Required
> +        private Layout<? extends Serializable> layout = 
> PatternLayout.createDefaultLayout();
> +
> +        @PluginElement("Filter")
> +        private Filter filter;
> +
> +        @PluginBuilderAttribute
> +        @Required
> +        private Target target = DEFAULT_TARGET;
> +
> +        @PluginBuilderAttribute
> +        @Required
> +        private String name;
> +
> +        @PluginBuilderAttribute
> +        private boolean ignoreExceptions = true;
> +
> +        public Builder setLayout(final Layout<? extends Serializable> 
> aLayout) {
> +            this.layout = aLayout;
> +            return this;
> +        }
> +
> +        public Builder setFilter(final Filter aFilter) {
> +            this.filter = aFilter;
> +            return this;
> +        }
> +
> +        public Builder setTarget(final Target aTarget) {
> +            this.target = aTarget;
> +            return this;
> +        }
> +
> +        public Builder setName(final String aName) {
> +            this.name <http://this.name/> = aName;
> +            return this;
> +        }
> +
> +        public Builder setIgnoreExceptions(final boolean 
> shouldIgnoreExceptions) {
> +            this.ignoreExceptions = shouldIgnoreExceptions;
> +            return this;
> +        }
> +
> +        @Override
> +        public FastConsoleAppender build() {
> +            return new FastConsoleAppender(name, layout, filter, 
> getManager(target, layout), ignoreExceptions, target);
> +        }
> +    }
> +
> +    private static OutputStreamManager getDefaultManager(final Target 
> target, final Layout<? extends Serializable> layout) {
> +        final OutputStream os = getOutputStream(target);
> +
> +        // LOG4J2-1176 DefaultConfiguration should not share 
> OutputStreamManager instances to avoid memory leaks.
> +        final String managerName = target.name <http://target.name/>() + '-' 
> + COUNT.get();
> +        return OutputStreamManager.getManager(managerName, new 
> FactoryData(os, managerName, layout), factory);
> +    }
> +
> +    private static OutputStreamManager getManager(final Target target, final 
> Layout<? extends Serializable> layout) {
> +        final OutputStream os = getOutputStream(target);
> +        final String managerName = target.name <http://target.name/>();
> +        return OutputStreamManager.getManager(managerName, new 
> FactoryData(os, managerName, layout), factory);
> +    }
> +
> +    private static OutputStream getOutputStream(final Target target) {
> +        OutputStream outputStream = target == Target.SYSTEM_OUT
> +            ? new FileOutputStream(FileDescriptor.out)
> +            : new FileOutputStream(FileDescriptor.err);
> +        return new CloseShieldOutputStream(outputStream);
> +    }
> +
> +    /**
> +     * Data to pass to factory method.
> +     */
> +    private static class FactoryData {
> +        private final OutputStream os;
> +        private final String name;
> +        private final Layout<? extends Serializable> layout;
> +
> +        /**
> +         * Constructor.
> +         *
> +         * @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 <http://this.name/> = type;
> +            this.layout = layout;
> +        }
> +    }
> +
> +    /**
> +     * Factory to create the Appender.
> +     */
> +    private static class ConsoleManagerFactory implements 
> ManagerFactory<OutputStreamManager, FactoryData> {
> +
> +        /**
> +         * Create 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 
> <http://data.name/>, data.layout, true);
> +        }
> +    }
> +
> +    public Target getTarget() {
> +        return target;
> +    }
> +
> +}
> 
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/06c55468/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java
>  
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/06c55468/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java>
> ----------------------------------------------------------------------
> diff --git 
> a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java
>  
> b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java
> index 0527709..a4ea02e 100644
> --- 
> a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java
> +++ 
> b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java
> @@ -57,12 +57,14 @@ public class Log4j2AppenderComparisonBenchmark {
>      private Logger rafLogger;
>      private Logger mmapLogger;
>      private Logger consoleLogger;
> +    private Logger fastConsoleLogger;
>      private Logger noopLogger;
>      private Logger rewriteLogger;
>      private Appender fileAppender;
>      private Appender rafAppender;
>      private Appender mmapAppender;
>      private Appender consoleAppender;
> +    private Appender fastConsoleAppender;
>      private Appender noopAppender;
>      private Appender rewriteAppender;
> 
> @@ -102,6 +104,7 @@ public class Log4j2AppenderComparisonBenchmark {
>          rafLogger = LogManager.getLogger("RAFLogger");
>          mmapLogger = LogManager.getLogger("MMapLogger");
>          consoleLogger = LogManager.getLogger("ConsoleLogger");
> +        fastConsoleLogger = LogManager.getLogger("FastConsoleLogger");
>          noopLogger = LogManager.getLogger("NoopLogger");
>          rewriteLogger = LogManager.getLogger("RewriteLogger");
> 
> @@ -109,6 +112,7 @@ public class Log4j2AppenderComparisonBenchmark {
>          rafAppender = ((org.apache.logging.log4j.core.Logger) 
> rafLogger).getAppenders().get("RandomAccessFile");
>          mmapAppender = ((org.apache.logging.log4j.core.Logger) 
> mmapLogger).getAppenders().get("MemoryMappedFile");
>          consoleAppender = ((org.apache.logging.log4j.core.Logger) 
> consoleLogger).getAppenders().get("Console");
> +        fastConsoleAppender = ((org.apache.logging.log4j.core.Logger) 
> fastConsoleLogger).getAppenders().get("FastConsole");
>          noopAppender = ((org.apache.logging.log4j.core.Logger) 
> noopLogger).getAppenders().get("NoOp");
>          rewriteAppender = ((org.apache.logging.log4j.core.Logger) 
> rewriteLogger).getAppenders().get("Rewrite");
>      }
> @@ -218,4 +222,18 @@ public class Log4j2AppenderComparisonBenchmark {
>      public void appenderConsole() {
>          consoleAppender.append(EVENT);
>      }
> +
> +    @BenchmarkMode(Mode.Throughput)
> +    @OutputTimeUnit(TimeUnit.SECONDS)
> +    @Benchmark
> +    public void end2endFastConsole() {
> +        fastConsoleLogger.debug(MESSAGE);
> +    }
> +
> +    @BenchmarkMode(Mode.Throughput)
> +    @OutputTimeUnit(TimeUnit.SECONDS)
> +    @Benchmark
> +    public void appenderFastConsole() {
> +        fastConsoleAppender.append(EVENT);
> +    }
>  }
> 
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/06c55468/log4j-perf/src/main/resources/log4j2-appenderComparison.xml
>  
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/06c55468/log4j-perf/src/main/resources/log4j2-appenderComparison.xml>
> ----------------------------------------------------------------------
> diff --git a/log4j-perf/src/main/resources/log4j2-appenderComparison.xml 
> b/log4j-perf/src/main/resources/log4j2-appenderComparison.xml
> index 741a225..8ad6327 100644
> --- a/log4j-perf/src/main/resources/log4j2-appenderComparison.xml
> +++ b/log4j-perf/src/main/resources/log4j2-appenderComparison.xml
> @@ -21,6 +21,9 @@
>          <Console name="Console" target="SYSTEM_OUT">
>              <PatternLayout pattern="%d %p [%t] %c{1} %X{transactionId} - 
> %m%n"/>
>          </Console>
> +        <FastConsole name="FastConsole" target="SYSTEM_OUT">
> +            <PatternLayout pattern="%d %p [%t] %c{1} %X{transactionId} - 
> %m%n"/>
> +        </FastConsole>
>          <File name="File" fileName="target/testlog4j2.log" 
> immediateFlush="false">
>              <PatternLayout pattern="%d %p [%t] %c{1} %X{transactionId} - 
> %m%n"/>
>          </File>
> @@ -55,6 +58,9 @@
>          <Logger name="ConsoleLogger" level="debug" additivity="false">
>              <AppenderRef ref="Console"/>
>          </Logger>
> +        <Logger name="FastConsoleLogger" level="debug" additivity="false">
> +            <AppenderRef ref="FastConsole"/>
> +        </Logger>
>          <Logger name="NoopLogger" level="debug" additivity="false">
>              <AppenderRef ref="NoOp"/>
>          </Logger>
> 
> 
> 
> 
> -- 
> Matt Sicker <[email protected] <mailto:[email protected]>>
> 
> 
> 
> -- 
>  
> 
> Mikael Ståldal
> Senior software developer 
> 
> Magine TV
> [email protected] <mailto:[email protected]>    
> Grev Turegatan 3  | 114 46 Stockholm, Sweden  |   www.magine.com  
> <http://www.magine.com/>
> 
> Privileged and/or Confidential Information may be contained in this message. 
> If you are not the addressee indicated in this message
> (or responsible for delivery of the message to such a person), you may not 
> copy or deliver this message to anyone. In such case, 
> you should destroy this message and kindly notify the sender by reply email.  
>  
> 
> 
> 
> -- 
> Matt Sicker <[email protected] <mailto:[email protected]>>

Reply via email to