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]>>
